diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..412eeda78 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index 60e6c3722..8a318550c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ -*.class - -# Package Files # -*.jar -*.war -*.ear - -/target/ -/nbactions.xml \ No newline at end of file +*.class + +# Package Files # +*.jar +*.war +*.ear + +/target/ +/nbactions.xml diff --git a/JacksonReplacement/JsonAnySetter.java b/JacksonReplacement/JsonAnySetter.java index 2bee382de..753b07117 100644 --- a/JacksonReplacement/JsonAnySetter.java +++ b/JacksonReplacement/JsonAnySetter.java @@ -1,12 +1,12 @@ -package com.darylbeattie.movies.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(value=ElementType.METHOD) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface JsonAnySetter { - -} +package com.darylbeattie.movies.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(value=ElementType.METHOD) +@Retention(value=RetentionPolicy.RUNTIME) +public @interface JsonAnySetter { + +} diff --git a/JacksonReplacement/JsonProperty.java b/JacksonReplacement/JsonProperty.java index 77be4f498..0b4980476 100644 --- a/JacksonReplacement/JsonProperty.java +++ b/JacksonReplacement/JsonProperty.java @@ -1,12 +1,12 @@ -package com.darylbeattie.movies.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) -@Retention(RetentionPolicy.RUNTIME) -public @interface JsonProperty { - String value() default ""; -} +package com.darylbeattie.movies.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JsonProperty { + String value() default ""; +} diff --git a/JacksonReplacement/JsonRootName.java b/JacksonReplacement/JsonRootName.java index 4f5450dfa..74522d25e 100644 --- a/JacksonReplacement/JsonRootName.java +++ b/JacksonReplacement/JsonRootName.java @@ -1,12 +1,12 @@ -package com.darylbeattie.movies.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface JsonRootName { - String value() default ""; -} +package com.darylbeattie.movies.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface JsonRootName { + String value() default ""; +} diff --git a/JacksonReplacement/ObjectMapper.java b/JacksonReplacement/ObjectMapper.java index 2150c721d..d904517a7 100644 --- a/JacksonReplacement/ObjectMapper.java +++ b/JacksonReplacement/ObjectMapper.java @@ -1,69 +1,69 @@ -package com.darylbeattie.movies.util; - -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.ParameterizedType; -import java.util.List; - -import org.json.JSONArray; -import org.json.JSONObject; - -public class ObjectMapper { - - /** - * This takes a JSON string and creates (and populates) an object of the given class - * with the data from that JSON string. It mimics the method signature of the jackson - * JSON API, so that we don't have to import the jackson library into this application. - * - * @param jsonString The JSON string to parse. - * @param objClass The class of object we want to create. - * @return The instantiation of that class, populated with data from the JSON object. - * @throws IOException If there was any kind of issue. - */ - public T readValue(String jsonString, Class objClass) throws IOException { - try { - return readValue(new JSONObject(jsonString), objClass); - } - catch (IOException ioe) { - throw ioe; - } - catch (Exception e) { - e.printStackTrace(); - throw new IOException(e); - } - } - - @SuppressWarnings("unchecked") - public T readValue(JSONObject json, Class objClass) throws IOException { - try { - //TODO Iterate through json object values and call the JsonAnySetter method on the unknown ones. - T obj = objClass.newInstance(); - for (Field f : objClass.getFields()) { - Annotation a = f.getAnnotation(JsonProperty.class); - if (List.class.equals(f.getType()) && (json.optJSONArray(((JsonProperty) a).value()) != null)) { // It's a list. - JSONArray jsonArray = json.optJSONArray(((JsonProperty) a).value()); - ParameterizedType listType = (ParameterizedType) f.getGenericType(); - Class subObj = (Class) listType.getActualTypeArguments()[0]; - List subObjList = ((Class>) f.getType()).newInstance(); - for (int i = 0; i < jsonArray.length(); i++) { - subObjList.add((R) readValue(jsonArray.getJSONObject(i), subObj)); - } - f.set(obj, subObjList); - } - else if (a != null) { - f.set(obj, json.opt(((JsonProperty) a).value())); - } - } - return obj; - } - catch (IOException ioe) { - throw ioe; - } - catch (Exception e) { - e.printStackTrace(); - throw new IOException(e); - } - } - +package com.darylbeattie.movies.util; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class ObjectMapper { + + /** + * This takes a JSON string and creates (and populates) an object of the given class + * with the data from that JSON string. It mimics the method signature of the jackson + * JSON API, so that we don't have to import the jackson library into this application. + * + * @param jsonString The JSON string to parse. + * @param objClass The class of object we want to create. + * @return The instantiation of that class, populated with data from the JSON object. + * @throws IOException If there was any kind of issue. + */ + public T readValue(String jsonString, Class objClass) throws IOException { + try { + return readValue(new JSONObject(jsonString), objClass); + } + catch (IOException ioe) { + throw ioe; + } + catch (Exception e) { + e.printStackTrace(); + throw new IOException(e); + } + } + + @SuppressWarnings("unchecked") + public T readValue(JSONObject json, Class objClass) throws IOException { + try { + //TODO Iterate through json object values and call the JsonAnySetter method on the unknown ones. + T obj = objClass.newInstance(); + for (Field f : objClass.getFields()) { + Annotation a = f.getAnnotation(JsonProperty.class); + if (List.class.equals(f.getType()) && (json.optJSONArray(((JsonProperty) a).value()) != null)) { // It's a list. + JSONArray jsonArray = json.optJSONArray(((JsonProperty) a).value()); + ParameterizedType listType = (ParameterizedType) f.getGenericType(); + Class subObj = (Class) listType.getActualTypeArguments()[0]; + List subObjList = ((Class>) f.getType()).newInstance(); + for (int i = 0; i < jsonArray.length(); i++) { + subObjList.add((R) readValue(jsonArray.getJSONObject(i), subObj)); + } + f.set(obj, subObjList); + } + else if (a != null) { + f.set(obj, json.opt(((JsonProperty) a).value())); + } + } + return obj; + } + catch (IOException ioe) { + throw ioe; + } + catch (Exception e) { + e.printStackTrace(); + throw new IOException(e); + } + } + } \ No newline at end of file diff --git a/JacksonReplacement/README.md b/JacksonReplacement/README.md index 71bdb8a7d..f8955d952 100644 --- a/JacksonReplacement/README.md +++ b/JacksonReplacement/README.md @@ -1,6 +1,6 @@ -Jackson Library Replacement -=========================== - -These files are provided by Darren Beattie as an example of how to replace the Jackson libraries with native libraries inside Android. - -They are provided without warrantee and if you modify them or find them useful, please let me know. +Jackson Library Replacement +=========================== + +These files are provided by Darren Beattie as an example of how to replace the Jackson libraries with native libraries inside Android. + +They are provided without warrantee and if you modify them or find them useful, please let me know. diff --git a/LICENCE.txt b/LICENCE.txt index 5ec82a48a..b49a4de81 100644 --- a/LICENCE.txt +++ b/LICENCE.txt @@ -1,648 +1,648 @@ - 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 . + 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 . diff --git a/src/main/java/com/omertron/themoviedbapi/MovieDbException.java b/src/main/java/com/omertron/themoviedbapi/MovieDbException.java index fd9fbbad3..a3d505471 100644 --- a/src/main/java/com/omertron/themoviedbapi/MovieDbException.java +++ b/src/main/java/com/omertron/themoviedbapi/MovieDbException.java @@ -1,87 +1,87 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of TheMovieDB API. - * - * TheMovieDB API 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 - * any later version. - * - * TheMovieDB API 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 TheMovieDB API. If not, see . - * - */ -package com.omertron.themoviedbapi; - -public class MovieDbException extends Exception { - - private static final long serialVersionUID = 1L; - - public enum MovieDbExceptionType { - /* - * Unknown error occured - */ - UNKNOWN_CAUSE, - /* - * URL is invalid - */ - INVALID_URL, - /* - * Page not found - */ - HTTP_404_ERROR, - /* - * The movie id was not found - */ - MOVIE_ID_NOT_FOUND, - /* - * Mapping failed from target to internal onbjects - */ - MAPPING_FAILED, - /* - * Error connecting to the service - */ - CONNECTION_ERROR, - /* - * Image was invalid - */ - INVALID_IMAGE, - /* - * Autorisation rejected - */ - AUTHORISATION_FAILURE, - /* - * Service Unavailable, usually temporary - */ - HTTP_503_ERROR; - } - - private final MovieDbExceptionType exceptionType; - private final String response; - - public MovieDbException(final MovieDbExceptionType exceptionType, final String response) { - super(); - this.exceptionType = exceptionType; - this.response = response; - } - - public MovieDbException(final MovieDbExceptionType exceptionType, final String response, final Throwable cause) { - super(cause); - this.exceptionType = exceptionType; - this.response = response; - } - - public MovieDbExceptionType getExceptionType() { - return exceptionType; - } - - public String getResponse() { - return response; - } -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of TheMovieDB API. + * + * TheMovieDB API 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 + * any later version. + * + * TheMovieDB API 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 TheMovieDB API. If not, see . + * + */ +package com.omertron.themoviedbapi; + +public class MovieDbException extends Exception { + + private static final long serialVersionUID = 1L; + + public enum MovieDbExceptionType { + /* + * Unknown error occured + */ + UNKNOWN_CAUSE, + /* + * URL is invalid + */ + INVALID_URL, + /* + * Page not found + */ + HTTP_404_ERROR, + /* + * The movie id was not found + */ + MOVIE_ID_NOT_FOUND, + /* + * Mapping failed from target to internal onbjects + */ + MAPPING_FAILED, + /* + * Error connecting to the service + */ + CONNECTION_ERROR, + /* + * Image was invalid + */ + INVALID_IMAGE, + /* + * Autorisation rejected + */ + AUTHORISATION_FAILURE, + /* + * Service Unavailable, usually temporary + */ + HTTP_503_ERROR; + } + + private final MovieDbExceptionType exceptionType; + private final String response; + + public MovieDbException(final MovieDbExceptionType exceptionType, final String response) { + super(); + this.exceptionType = exceptionType; + this.response = response; + } + + public MovieDbException(final MovieDbExceptionType exceptionType, final String response, final Throwable cause) { + super(cause); + this.exceptionType = exceptionType; + this.response = response; + } + + public MovieDbExceptionType getExceptionType() { + return exceptionType; + } + + public String getResponse() { + return response; + } +} diff --git a/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java b/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java index f2502bb13..f644b6584 100644 --- a/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java +++ b/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java @@ -1,2060 +1,2060 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of TheMovieDB API. - * - * TheMovieDB API 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 - * any later version. - * - * TheMovieDB API 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 TheMovieDB API. If not, see . - * - */ -package com.omertron.themoviedbapi; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import static com.omertron.themoviedbapi.tools.ApiUrl.*; -import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.methods.HttpGet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.yamj.api.common.http.CommonHttpClient; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.omertron.themoviedbapi.MovieDbException.MovieDbExceptionType; -import com.omertron.themoviedbapi.model.*; -import com.omertron.themoviedbapi.results.TmdbResultsList; -import com.omertron.themoviedbapi.results.TmdbResultsMap; -import com.omertron.themoviedbapi.tools.ApiUrl; -import com.omertron.themoviedbapi.tools.WebBrowser; -import com.omertron.themoviedbapi.wrapper.*; - -/** - * The MovieDb API

This is for version 3 of the API as specified here: http://help.themoviedb.org/kb/api/about-3 - * - * @author stuart.boston - */ -public class TheMovieDbApi { - - private static final Logger LOG = LoggerFactory.getLogger(TheMovieDbApi.class); - private static final String FAILED_KEYWORD = "Failed to get keyword: {}"; - private String apiKey; - private CommonHttpClient httpClient; - private TmdbConfiguration tmdbConfig; - // API Methods - private static final String BASE_MOVIE = "movie/"; - private static final String BASE_PERSON = "person/"; - private static final String BASE_COMPANY = "company/"; - private static final String BASE_GENRE = "genre/"; - private static final String BASE_AUTH = "authentication/"; - private static final String BASE_COLLECTION = "collection/"; - private static final String BASE_ACCOUNT = "account/"; - private static final String BASE_SEARCH = "search/"; - private static final String BASE_LIST = "list/"; - private static final String BASE_KEYWORD = "keyword/"; - private static final String BASE_JOB = "job/"; - private static final String BASE_DISCOVER = "discover/"; - // Jackson JSON configuration - private static ObjectMapper mapper = new ObjectMapper(); - - /** - * API for The Movie Db. - * - * @param apiKey - * @throws MovieDbException - */ - public TheMovieDbApi(String apiKey) throws MovieDbException { - this(apiKey, null); - } - - /** - * API for The Movie Db. - * - * @param apiKey - * @param httpClient The httpClient to use for web requests. - * @throws MovieDbException - */ - public TheMovieDbApi(String apiKey, CommonHttpClient httpClient) throws MovieDbException { - this.apiKey = apiKey; - this.httpClient = httpClient; - - ApiUrl apiUrl = new ApiUrl(apiKey, "configuration"); - URL configUrl = apiUrl.buildUrl(); - String webpage = requestWebPage(configUrl); - - try { - WrapperConfig wc = mapper.readValue(webpage, WrapperConfig.class); - tmdbConfig = wc.getTmdbConfiguration(); - } catch (IOException ex) { - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, "Failed to read configuration", ex); - } - } - - /** - * Get the API key that is to be used - * - */ - public String getApiKey() { - return apiKey; - } - - private String requestWebPage(URL url) throws MovieDbException { - return requestWebPage(url, null, Boolean.FALSE); - } - - private String requestWebPage(URL url, String jsonBody) throws MovieDbException { - return requestWebPage(url, jsonBody, Boolean.FALSE); - } - - private String requestWebPage(URL url, String jsonBody, boolean isDeleteRequest) throws MovieDbException { - // use HTTP client implementation - if (httpClient != null) { - try { - HttpGet httpGet = new HttpGet(url.toURI()); - httpGet.addHeader("accept", "application/json"); - - if (StringUtils.isNotBlank(jsonBody)) { - // TODO: Add the json body to the request - throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Unable to proces JSON request"); - } - - if (isDeleteRequest) { - //TODO: Handle delete request - throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Unable to proces delete request"); - } - - return httpClient.requestContent(httpGet); - } catch (URISyntaxException ex) { - throw new MovieDbException(MovieDbException.MovieDbExceptionType.CONNECTION_ERROR, null, ex); - } catch (IOException ex) { - throw new MovieDbException(MovieDbException.MovieDbExceptionType.CONNECTION_ERROR, null, ex); - } catch (RuntimeException ex) { - throw new MovieDbException(MovieDbException.MovieDbExceptionType.HTTP_503_ERROR, "Service Unavailable", ex); - } - } - - // use web browser - return WebBrowser.request(url, jsonBody, isDeleteRequest); - } - - /** - * Set the proxy information - * - * @param host - * @param port - * @param username - * @param password - */ - public void setProxy(String host, String port, String username, String password) { - // should be set in HTTP client already - if (httpClient != null) { - return; - } - - WebBrowser.setProxyHost(host); - WebBrowser.setProxyPort(port); - WebBrowser.setProxyUsername(username); - WebBrowser.setProxyPassword(password); - } - - /** - * Set the connection and read time out values - * - * @param connect - * @param read - */ - public void setTimeout(int connect, int read) { - // should be set in HTTP client already - if (httpClient != null) { - return; - } - - WebBrowser.setWebTimeoutConnect(connect); - WebBrowser.setWebTimeoutRead(read); - } - - /** - * Compare the MovieDB object with a title & year - * - * @param moviedb The moviedb object to compare too - * @param title The title of the movie to compare - * @param year The year of the movie to compare exact match - * @return True if there is a match, False otherwise. - */ - public static boolean compareMovies(MovieDb moviedb, String title, String year) { - return compareMovies(moviedb, title, year, 0); - } - - /** - * Compare the MovieDB object with a title & year - * - * @param moviedb The moviedb object to compare too - * @param title The title of the movie to compare - * @param year The year of the movie to compare - * @param maxDistance The Levenshtein Distance between the two titles. 0 = exact match - * @return True if there is a match, False otherwise. - */ - public static boolean compareMovies(MovieDb moviedb, String title, String year, int maxDistance) { - if ((moviedb == null) || (StringUtils.isBlank(title))) { - return Boolean.FALSE; - } - - if (isValidYear(year) && isValidYear(moviedb.getReleaseDate())) { - // Compare with year - String movieYear = moviedb.getReleaseDate().substring(0, 4); - if (movieYear.equals(year)) { - if (compareDistance(moviedb.getOriginalTitle(), title, maxDistance)) { - return Boolean.TRUE; - } - - if (compareDistance(moviedb.getTitle(), title, maxDistance)) { - return Boolean.TRUE; - } - } - } - - // Compare without year - if (compareDistance(moviedb.getOriginalTitle(), title, maxDistance)) { - return Boolean.TRUE; - } - - if (compareDistance(moviedb.getTitle(), title, maxDistance)) { - return Boolean.TRUE; - } - - return Boolean.FALSE; - } - - /** - * Compare the Levenshtein Distance between the two strings - * - * @param title1 - * @param title2 - * @param distance - */ - private static boolean compareDistance(String title1, String title2, int distance) { - return (StringUtils.getLevenshteinDistance(title1, title2) <= distance); - } - - /** - * Check the year is not blank or UNKNOWN - * - * @param year - */ - private static boolean isValidYear(String year) { - return (StringUtils.isNotBlank(year) && !year.equals("UNKNOWN")); - } - - // - /** - * Get the configuration information - */ - public TmdbConfiguration getConfiguration() { - return tmdbConfig; - } - - /** - * Generate the full image URL from the size and image path - * - * @param imagePath - * @param requiredSize - * @throws MovieDbException - */ - public URL createImageUrl(String imagePath, String requiredSize) throws MovieDbException { - if (!tmdbConfig.isValidSize(requiredSize)) { - throw new MovieDbException(MovieDbExceptionType.INVALID_IMAGE, requiredSize); - } - - StringBuilder sb = new StringBuilder(tmdbConfig.getBaseUrl()); - sb.append(requiredSize); - sb.append(imagePath); - try { - return (new URL(sb.toString())); - } catch (MalformedURLException ex) { - LOG.warn("Failed to create image URL: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.INVALID_URL, sb.toString(), ex); - } - } - // - - // - /** - * This method is used to generate a valid request token for user based authentication. - * - * A request token is required in order to request a session id. - * - * You can generate any number of request tokens but they will expire after 60 minutes. - * - * As soon as a valid session id has been created the token will be destroyed. - * - * @throws MovieDbException - */ - public TokenAuthorisation getAuthorisationToken() throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_AUTH, "token/new"); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, TokenAuthorisation.class); - } catch (IOException ex) { - LOG.warn("Failed to get Authorisation Token: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.AUTHORISATION_FAILURE, webpage, ex); - } - } - - /** - * This method is used to generate a session id for user based authentication. - * - * A session id is required in order to use any of the write methods. - * - * @param token - * @throws MovieDbException - */ - public TokenSession getSessionToken(TokenAuthorisation token) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_AUTH, "session/new"); - - if (!token.getSuccess()) { - LOG.warn("Authorisation token was not successful!"); - throw new MovieDbException(MovieDbExceptionType.AUTHORISATION_FAILURE, "Authorisation token was not successful!"); - } - - apiUrl.addArgument(PARAM_TOKEN, token.getRequestToken()); - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, TokenSession.class); - } catch (IOException ex) { - LOG.warn("Failed to get Session Token: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to generate a guest session id. - * - * A guest session can be used to rate movies without having a registered TMDb user account. - * - * You should only generate a single guest session per user (or device) as you will be able to attach the ratings to a TMDb user - * account in the future. - * - * There are also IP limits in place so you should always make sure it's the end user doing the guest session actions. - * - * If a guest session is not used for the first time within 24 hours, it will be automatically discarded. - * - * @throws MovieDbException - */ - public TokenSession getGuestSessionToken() throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_AUTH, "guest_session/new"); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, TokenSession.class); - } catch (IOException ex) { - LOG.warn("Failed to get Session Token: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the basic information for an account. You will need to have a valid session id. - * - * - * @throws MovieDbException - */ - public Account getAccount(String sessionId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT.replace("/", "")); - - apiUrl.addArgument(PARAM_SESSION, sessionId); - - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, Account.class); - } catch (IOException ex) { - LOG.warn("Failed to get Session Token: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - public List getFavoriteMovies(String sessionId, int accountId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/favorite_movies"); - apiUrl.addArgument(PARAM_SESSION, sessionId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, WrapperMovie.class).getMovies(); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - public StatusCode changeFavoriteStatus(String sessionId, int accountId, Integer movieId, boolean isFavorite) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/favorite"); - - apiUrl.addArgument(PARAM_SESSION, sessionId); - - HashMap body = new HashMap(); - body.put("movie_id", movieId); - body.put("favorite", isFavorite); - String jsonBody = convertToJson(body); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url, jsonBody); - - try { - return mapper.readValue(webpage, StatusCode.class); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Add a movie to an account's watch list. - */ - public StatusCode addToWatchList(String sessionId, int accountId, Integer movieId) throws MovieDbException { - return modifyWatchList(sessionId, accountId, movieId, true); - } - - /** - * Remove a movie from an account's watch list. - */ - public StatusCode removeFromWatchList(String sessionId, int accountId, Integer movieId) throws MovieDbException { - return modifyWatchList(sessionId, accountId, movieId, false); - } - - private StatusCode modifyWatchList(String sessionId, int accountId, Integer movieId, boolean add) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/movie_watchlist"); - - apiUrl.addArgument(PARAM_SESSION, sessionId); - - HashMap body = new HashMap(); - body.put("movie_id", movieId); - body.put("movie_watchlist", add); - String jsonBody = convertToJson(body); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url, jsonBody); - - try { - return mapper.readValue(webpage, StatusCode.class); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - // No account functions - // - // - /** - * This method is used to retrieve all of the basic movie information. - * - * It will return the single highest rated poster and backdrop. - * - * @param movieId - * @param language - * @throws MovieDbException - */ - public MovieDb getMovieInfo(int movieId, String language, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE); - - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - try { - return mapper.readValue(webpage, MovieDb.class); - } catch (IOException ex) { - LOG.warn("Failed to get movie info: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve all of the basic movie information. - * - * It will return the single highest rated poster and backdrop. - * - * @param imdbId - * @param language - * @throws MovieDbException - */ - public MovieDb getMovieInfoImdb(String imdbId, String language, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE); - - apiUrl.addArgument(PARAM_ID, imdbId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - try { - return mapper.readValue(webpage, MovieDb.class); - } catch (IOException ex) { - LOG.warn("Failed to get movie info: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve all of the alternative titles we have for a particular movie. - * - * @param movieId - * @param country - * @throws MovieDbException - */ - public TmdbResultsList getMovieAlternativeTitles(int movieId, String country, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/alternative_titles"); - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(country)) { - apiUrl.addArgument(PARAM_COUNTRY, country); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - try { - WrapperAlternativeTitles wrapper = mapper.readValue(webpage, WrapperAlternativeTitles.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getTitles()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie alternative titles: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the cast information for a specific movie id. - * - * TODO: Add a function to enrich the data with the people methods - * - * @param movieId - * @throws MovieDbException - */ - public TmdbResultsList getMovieCasts(int movieId, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/casts"); - apiUrl.addArgument(PARAM_ID, movieId); - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovieCasts wrapper = mapper.readValue(webpage, WrapperMovieCasts.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie casts: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method should be used when you’re wanting to retrieve all of the images for a particular movie. - * - * @param movieId - * @param language - * @throws MovieDbException - */ - public TmdbResultsList getMovieImages(int movieId, String language, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/images"); - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperImages wrapper = mapper.readValue(webpage, WrapperImages.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie images: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve all of the keywords that have been added to a particular movie. - * - * Currently, only English keywords exist. - * - * @param movieId - * @throws MovieDbException - */ - public TmdbResultsList getMovieKeywords(int movieId, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/keywords"); - apiUrl.addArgument(PARAM_ID, movieId); - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovieKeywords wrapper = mapper.readValue(webpage, WrapperMovieKeywords.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getKeywords()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie keywords: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve all of the release and certification data we have for a specific movie. - * - * @param movieId - * @param language - * @throws MovieDbException - */ - public TmdbResultsList getMovieReleaseInfo(int movieId, String language, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/releases"); - apiUrl.addArgument(PARAM_ID, movieId); - apiUrl.addArgument(PARAM_LANGUAGE, language); - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperReleaseInfo wrapper = mapper.readValue(webpage, WrapperReleaseInfo.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getCountries()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie release information: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve all of the trailers for a particular movie. - * - * Supported sites are YouTube and QuickTime. - * - * @param movieId - * @param language - * @throws MovieDbException - */ - public TmdbResultsList getMovieTrailers(int movieId, String language, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/trailers"); - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperTrailers wrapper = mapper.readValue(webpage, WrapperTrailers.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie trailers: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve a list of the available translations for a specific movie. - * - * @param movieId - * @throws MovieDbException - */ - public TmdbResultsList getMovieTranslations(int movieId, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/translations"); - apiUrl.addArgument(PARAM_ID, movieId); - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperTranslations wrapper = mapper.readValue(webpage, WrapperTranslations.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getTranslations()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie tranlations: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * The similar movies method will let you retrieve the similar movies for a particular movie. - * - * This data is created dynamically but with the help of users votes on TMDb. - * - * The data is much better with movies that have more keywords - * - * @param movieId - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList getSimilarMovies(int movieId, String language, int page, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/similar_movies"); - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get similar movies: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - public TmdbResultsList getReviews(int movieId, String language, int page, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/reviews"); - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperReviews wrapper = mapper.readValue(webpage, WrapperReviews.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getReviews()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get reviews: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the lists that the movie belongs to - * - * @param movieId - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList getMovieLists(int movieId, String language, int page, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/lists"); - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovieList wrapper = mapper.readValue(webpage, WrapperMovieList.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovieList()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie lists: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the changes for a specific movie id. - * - * Changes are grouped by key, and ordered by date in descending order. - * - * By default, only the last 24 hours of changes are returned. - * - * The maximum number of days that can be returned in a single request is 14. - * - * The language is present on fields that are translatable. - * - * TODO: DOES NOT WORK AT THE MOMENT. This is due to the "value" item changing type in the ChangeItem - * - * @param movieId - * @param startDate the start date of the changes, optional - * @param endDate the end date of the changes, optional - * @throws MovieDbException - */ - public TmdbResultsMap> getMovieChanges(int movieId, String startDate, String endDate) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/changes"); - apiUrl.addArgument(PARAM_ID, movieId); - - if (StringUtils.isNotBlank(startDate)) { - apiUrl.addArgument(PARAM_START_DATE, startDate); - } - - if (StringUtils.isNotBlank(endDate)) { - apiUrl.addArgument(PARAM_END_DATE, endDate); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - try { - WrapperChanges wrapper = mapper.readValue(webpage, WrapperChanges.class); - - Map> results = new HashMap>(); - for (ChangeKeyItem changeItem : wrapper.getChangedItems()) { - results.put(changeItem.getKey(), changeItem.getChangedItems()); - } - - return new TmdbResultsMap>(results); - } catch (IOException ex) { - LOG.warn("Failed to get movie changes: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - - } - - /** - * This method is used to retrieve the newest movie that was added to TMDb. - * - */ - public MovieDb getLatestMovie() throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/latest"); - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, MovieDb.class); - } catch (IOException ex) { - LOG.warn("Failed to get latest movie: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the list of upcoming movies. - * - * This list refreshes every day. - * - * The maximum number of items this list will include is 100. - * - * @throws MovieDbException - */ - public TmdbResultsList getUpcoming(String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "upcoming"); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get upcoming movies: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - - } - - /** - * This method is used to retrieve the movies currently in theatres. - * - * This is a curated list that will normally contain 100 movies. The default response will return 20 movies. - * - * TODO: Implement more than 20 movies - * - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList getNowPlayingMovies(String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "now-playing"); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get now playing movies: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve the daily movie popularity list. - * - * This list is updated daily. The default response will return 20 movies. - * - * TODO: Implement more than 20 movies - * - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList getPopularMovieList(String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "popular"); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get popular movie list: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve the top rated movies that have over 10 votes on TMDb. - * - * The default response will return 20 movies. - * - * TODO: Implement more than 20 movies - * - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList getTopRatedMovies(String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "top-rated"); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get top rated movies: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - public List getRatedMovies(String sessionId, int accountId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/rated_movies"); - apiUrl.addArgument(PARAM_SESSION, sessionId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, WrapperMovie.class).getMovies(); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method lets users rate a movie. - * - * A valid session id is required. - * - * @param sessionId - * @param movieId - * @param rating - * @throws MovieDbException - */ - public boolean postMovieRating(String sessionId, Integer movieId, Integer rating) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, movieId + "/rating"); - - apiUrl.addArgument(PARAM_SESSION, sessionId); - - if (rating < 0 || rating > 10) { - throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Rating out of range"); - } - - String jsonBody = convertToJson(Collections.singletonMap("value", rating)); - LOG.info("Body: {}", jsonBody); - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url, jsonBody); - - try { - StatusCode status = mapper.readValue(webpage, StatusCode.class); - LOG.info("Status: {}", status); - int code = status.getStatusCode(); - return code == 12; - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * This method is used to retrieve all of the basic information about a movie collection. - * - * You can get the ID needed for this method by making a getMovieInfo request for the belongs_to_collection. - * - * @param collectionId - * @param language - * @throws MovieDbException - */ - public CollectionInfo getCollectionInfo(int collectionId, String language) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COLLECTION); - apiUrl.addArgument(PARAM_ID, collectionId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, CollectionInfo.class); - } catch (IOException ex) { - LOG.warn("Failed to get collection information: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get all of the images for a particular collection by collection id. - * - * @param collectionId - * @param language - * @throws MovieDbException - */ - public TmdbResultsList getCollectionImages(int collectionId, String language) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COLLECTION, "/images"); - apiUrl.addArgument(PARAM_ID, collectionId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperImages wrapper = mapper.readValue(webpage, WrapperImages.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getAll(ArtworkType.POSTER, ArtworkType.BACKDROP)); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get collection images: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * This method is used to retrieve all of the basic person information. - * - * It will return the single highest rated profile image. - * - * @param personId - * @throws MovieDbException - */ - public Person getPersonInfo(int personId, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON); - - apiUrl.addArgument(PARAM_ID, personId); - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, Person.class); - } catch (IOException ex) { - LOG.warn("Failed to get movie info: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve all of the cast & crew information for the person. - * - * It will return the single highest rated poster for each movie record. - * - * @param personId - * @throws MovieDbException - */ - public TmdbResultsList getPersonCredits(int personId, String... appendToResponse) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/credits"); - - apiUrl.addArgument(PARAM_ID, personId); - apiUrl.appendToResponse(appendToResponse); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperPersonCredits wrapper = mapper.readValue(webpage, WrapperPersonCredits.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get person credits: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve all of the profile images for a person. - * - * @param personId - * @throws MovieDbException - */ - public TmdbResultsList getPersonImages(int personId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/images"); - - apiUrl.addArgument(PARAM_ID, personId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperImages wrapper = mapper.readValue(webpage, WrapperImages.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getAll(ArtworkType.PROFILE)); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get person images: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the changes for a specific person id. - * - * Changes are grouped by key, and ordered by date in descending order. - * - * By default, only the last 24 hours of changes are returned. - * - * The maximum number of days that can be returned in a single request is 14. - * - * The language is present on fields that are translatable. - * - * @param personId - * @param startDate - * @param endDate - * @throws MovieDbException - */ - public void getPersonChanges(int personId, String startDate, String endDate) throws MovieDbException { - throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Not implemented yet"); - } - - /** - * Get the list of popular people on The Movie Database. - * - * This list refreshes every day. - * - * @return - * @throws MovieDbException - */ - public TmdbResultsList getPersonPopular() throws MovieDbException { - return getPersonPopular(0); - } - - /** - * Get the list of popular people on The Movie Database. - * - * This list refreshes every day. - * - * @param page - * @return - * @throws MovieDbException - */ - public TmdbResultsList getPersonPopular(int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/popular"); - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperPersonList wrapper = mapper.readValue(webpage, WrapperPersonList.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getPersonList()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get person images: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the latest person id. - * - * @throws MovieDbException - */ - public Person getPersonLatest() throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/latest"); - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, Person.class); - } catch (IOException ex) { - LOG.warn("Failed to get latest person: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * This method is used to retrieve the basic information about a production company on TMDb. - * - * @param companyId - * @throws MovieDbException - */ - public Company getCompanyInfo(int companyId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COMPANY); - - apiUrl.addArgument(PARAM_ID, companyId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, Company.class); - } catch (IOException ex) { - LOG.warn("Failed to get company information: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method is used to retrieve the movies associated with a company. - * - * These movies are returned in order of most recently released to oldest. The default response will return 20 movies per page. - * - * TODO: Implement more than 20 movies - * - * @param companyId - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList getCompanyMovies(int companyId, String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COMPANY, "/movies"); - - apiUrl.addArgument(PARAM_ID, companyId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperCompanyMovies wrapper = mapper.readValue(webpage, WrapperCompanyMovies.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get company movies: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * You can use this method to retrieve the list of genres used on TMDb. - * - * These IDs will correspond to those found in movie calls. - * - * @param language - */ - public TmdbResultsList getGenreList(String language) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_GENRE, "/list"); - apiUrl.addArgument(PARAM_LANGUAGE, language); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperGenres wrapper = mapper.readValue(webpage, WrapperGenres.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getGenres()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get genre list: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get a list of movies per genre. - * - * It is important to understand that only movies with more than 10 votes get listed. - * - * This prevents movies from 1 10/10 rating from being listed first and for the first 5 pages. - * - * @param genreId - * @param language - * @param page - */ - public TmdbResultsList getGenreMovies(int genreId, String language, int page, boolean includeAllMovies) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_GENRE, "/movies"); - apiUrl.addArgument(PARAM_ID, genreId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - apiUrl.addArgument(PARAM_INCLUDE_ALL_MOVIES, includeAllMovies); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get genre movie list: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * Search Movies This is a good starting point to start finding movies on TMDb. - * - * @param movieName - * @param searchYear Limit the search to the provided year. Zero (0) will get all years - * @param language The language to include. Can be blank/null. - * @param includeAdult true or false to include adult titles in the search - * @param page The page of results to return. 0 to get the default (first page) - * @throws MovieDbException - */ - public TmdbResultsList searchMovie(String movieName, int searchYear, String language, boolean includeAdult, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "movie"); - if (StringUtils.isNotBlank(movieName)) { - apiUrl.addArgument(PARAM_QUERY, movieName); - } - - if (searchYear > 0) { - apiUrl.addArgument(PARAM_YEAR, Integer.toString(searchYear)); - } - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - apiUrl.addArgument(PARAM_ADULT, Boolean.toString(includeAdult)); - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); - } - - URL url = apiUrl.buildUrl(); - - String webpage = requestWebPage(url); - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to find movie: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - - } - - /** - * Search for collections by name. - * - * @param query - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList searchCollection(String query, String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "collections"); - - if (StringUtils.isNotBlank(query)) { - apiUrl.addArgument(PARAM_QUERY, query); - } - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); - } - - URL url = apiUrl.buildUrl(); - - String webpage = requestWebPage(url); - try { - WrapperCollection wrapper = mapper.readValue(webpage, WrapperCollection.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to find collection: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This is a good starting point to start finding people on TMDb. - * - * The idea is to be a quick and light method so you can iterate through people quickly. - * - * @param personName - * @param includeAdult - * @param page - * @throws MovieDbException - */ - public TmdbResultsList searchPeople(String personName, boolean includeAdult, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "person"); - apiUrl.addArgument(PARAM_QUERY, personName); - apiUrl.addArgument(PARAM_ADULT, includeAdult); - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperPerson wrapper = mapper.readValue(webpage, WrapperPerson.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to find person: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Search for lists by name and description. - * - * @param query - * @param language - * @param page - * @throws MovieDbException - */ - public TmdbResultsList searchList(String query, String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "list"); - - if (StringUtils.isNotBlank(query)) { - apiUrl.addArgument(PARAM_QUERY, query); - } - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); - } - - URL url = apiUrl.buildUrl(); - - String webpage = requestWebPage(url); - try { - WrapperMovieList wrapper = mapper.readValue(webpage, WrapperMovieList.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovieList()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to find list: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Search Companies. - * - * You can use this method to search for production companies that are part of TMDb. The company IDs will map to those returned - * on movie calls. - * - * http://help.themoviedb.org/kb/api/search-companies - * - * @param companyName - * @param page - * @throws MovieDbException - */ - public TmdbResultsList searchCompanies(String companyName, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "company"); - apiUrl.addArgument(PARAM_QUERY, companyName); - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - try { - WrapperCompany wrapper = mapper.readValue(webpage, WrapperCompany.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to find company: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Search for keywords by name - * - * @param query - * @param page - * @throws MovieDbException - */ - public TmdbResultsList searchKeyword(String query, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "keyword"); - - if (StringUtils.isNotBlank(query)) { - apiUrl.addArgument(PARAM_QUERY, query); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); - } - - URL url = apiUrl.buildUrl(); - - String webpage = requestWebPage(url); - try { - WrapperKeywords wrapper = mapper.readValue(webpage, WrapperKeywords.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to find keyword: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * Get a list by its ID - * - * @param listId - * @return The list and its items - * @throws MovieDbException - */ - public MovieDbList getList(String listId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST); - apiUrl.addArgument(PARAM_ID, listId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, MovieDbList.class); - } catch (IOException ex) { - LOG.warn("Failed to get list: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get all lists of a given user - * - * @return The lists - * @throws MovieDbException - */ - public List getUserLists(String sessionId, int accountID) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountID + "/lists"); - apiUrl.addArgument(PARAM_SESSION, sessionId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, WrapperMovieDbList.class).getLists(); - } catch (IOException ex) { - LOG.warn("Failed to get lists: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method lets users create a new list. A valid session id is required. - * - * @return The list id - * @throws MovieDbException - */ - public String createList(String sessionId, String name, String description) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, "list"); - apiUrl.addArgument(PARAM_SESSION, sessionId); - - HashMap body = new HashMap(); - body.put("name", StringUtils.trimToEmpty(name)); - body.put("description", StringUtils.trimToEmpty(description)); - - String jsonBody = convertToJson(body); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url, jsonBody); - - - try { - return mapper.readValue(webpage, MovieDbListStatus.class).getListId(); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Check to see if a movie ID is already added to a list. - * - * @return true if the movie is on the list - * @throws MovieDbException - */ - public boolean isMovieOnList(String listId, Integer movieId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST, listId + "/item_status"); - apiUrl.addArgument("movie_id", movieId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, ListItemStatus.class).isItemPresent(); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method lets users add new movies to a list that they created. A valid session id is required. - * - * @return true if the movie is on the list - * @throws MovieDbException - */ - public StatusCode addMovieToList(String sessionId, String listId, Integer movieId) throws MovieDbException { - return modifyMovieList(sessionId, listId, movieId, "/add_item"); - } - - /** - * This method lets users remove movies from a list that they created. A valid session id is required. - * - * @return true if the movie is on the list - * @throws MovieDbException - */ - public StatusCode removeMovieFromList(String sessionId, String listId, Integer movieId) throws MovieDbException { - return modifyMovieList(sessionId, listId, movieId, "/remove_item"); - } - - private StatusCode modifyMovieList(String sessionId, String listId, Integer movieId, String operation) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST, listId + operation); - - apiUrl.addArgument(PARAM_SESSION, sessionId); - - String jsonBody = convertToJson(Collections.singletonMap("media_id", movieId + "")); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url, jsonBody); - - try { - return mapper.readValue(webpage, StatusCode.class); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * Get the list of movies on an accounts watchlist. - * - * @return The watchlist of the user - * @throws MovieDbException - */ - public List getWatchList(String sessionId, int accountId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/movie_watchlist"); - apiUrl.addArgument(PARAM_SESSION, sessionId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, WrapperMovie.class).getMovies(); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - /** - * This method lets users delete a list that they created. A valid session id is required. - * - * @throws MovieDbException - */ - public StatusCode deleteMovieList(String sessionId, String listId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST, listId); - - apiUrl.addArgument(PARAM_SESSION, sessionId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url, null, true); - - - try { - return mapper.readValue(webpage, StatusCode.class); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * Get the basic information for a specific keyword id. - * - * @param keywordId - * @return - * @throws MovieDbException - */ - public Keyword getKeyword(String keywordId) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_KEYWORD); - apiUrl.addArgument(PARAM_ID, keywordId); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - return mapper.readValue(webpage, Keyword.class); - } catch (IOException ex) { - LOG.warn(FAILED_KEYWORD, ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - - } - - /** - * Get the list of movies for a particular keyword by id. - * - * @param keywordId - * @param language - * @param page - * @return List of movies with the keyword - * @throws MovieDbException - */ - public TmdbResultsList getKeywordMovies(String keywordId, String language, int page) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_KEYWORD, "/movies"); - apiUrl.addArgument(PARAM_ID, keywordId); - - if (StringUtils.isNotBlank(language)) { - apiUrl.addArgument(PARAM_LANGUAGE, language); - } - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperKeywordMovies wrapper = mapper.readValue(webpage, WrapperKeywordMovies.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get top rated movies: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - - } - // - - // - /** - * Get a list of movie ids that have been edited. By default we show the last 24 hours and only 100 items per page. The maximum - * number of days that can be returned in a single request is 14. You can then use the movie changes API to get the actual data - * that has been changed. Please note that the change log system to support this was changed on October 5, 2012 and will only - * show movies that have been edited since. - * - * @param page - * @param startDate the start date of the changes, optional - * @param endDate the end date of the changes, optional - * @return List of changed movie - * @throws MovieDbException - */ - public TmdbResultsList getMovieChangesList(int page, String startDate, String endDate) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/changes"); - - if (page > 0) { - apiUrl.addArgument(PARAM_PAGE, page); - } - - if (StringUtils.isNotBlank(startDate)) { - apiUrl.addArgument(PARAM_START_DATE, startDate); - } - - if (StringUtils.isNotBlank(endDate)) { - apiUrl.addArgument(PARAM_END_DATE, endDate); - } - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - try { - WrapperMovieChanges wrapper = mapper.readValue(webpage, WrapperMovieChanges.class); - - TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get movie changes: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - - public void getPersonChangesList(int page, String startDate, String endDate) throws MovieDbException { - throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Not implemented yet"); - } - // - - // - public TmdbResultsList getJobs() throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_JOB, "/list"); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperJobList wrapper = mapper.readValue(webpage, WrapperJobList.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getJobs()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get job list: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - // - /** - * Discover movies by different types of data like average rating, number of votes, genres and certifications. - * - * You can alternatively create a "discover" object and pass it to this method to cut out the requirement for all of these - * parameters - * - * @param page Minimum value is 1 - * @param language ISO 639-1 code. - * @param sortBy Available options are vote_average.desc, vote_average.asc, release_date.desc, release_date.asc, - * popularity.desc, popularity.asc - * @param includeAdult Toggle the inclusion of adult titles - * @param year Filter the results release dates to matches that include this value - * @param primaryReleaseYear Filter the results so that only the primary release date year has this value - * @param voteCountGte Only include movies that are equal to, or have a vote count higher than this value - * @param voteAverageGte Only include movies that are equal to, or have a higher average rating than this value - * @param withGenres Only include movies with the specified genres. Expected value is an integer (the id of a genre). Multiple - * values can be specified. Comma separated indicates an 'AND' query, while a pipe (|) separated value indicates an 'OR'. - * @param releaseDateGte The minimum release to include. Expected format is YYYY-MM-DD - * @param releaseDateLte The maximum release to include. Expected format is YYYY-MM-DD - * @param certificationCountry Only include movies with certifications for a specific country. When this value is specified, - * 'certificationLte' is required. A ISO 3166-1 is expected. - * @param certificationLte Only include movies with this certification and lower. Expected value is a valid certification for - * the specified 'certificationCountry'. - * @param withCompanies Filter movies to include a specific company. Expected value is an integer (the id of a company). They - * can be comma separated to indicate an 'AND' query. - * @return - * @throws MovieDbException - */ - public TmdbResultsList getDiscover(int page, String language, String sortBy, boolean includeAdult, int year, - int primaryReleaseYear, int voteCountGte, float voteAverageGte, String withGenres, String releaseDateGte, - String releaseDateLte, String certificationCountry, String certificationLte, String withCompanies) throws MovieDbException { - - Discover discover = new Discover(); - discover.page(page) - .language(language) - .sortBy(sortBy) - .includeAdult(includeAdult) - .year(year) - .primaryReleaseYear(primaryReleaseYear) - .voteCountGte(voteCountGte) - .voteAverageGte(voteAverageGte) - .withGenres(withGenres) - .releaseDateGte(releaseDateGte) - .releaseDateLte(releaseDateLte) - .certificationCountry(certificationCountry) - .certificationLte(certificationLte) - .withCompanies(withCompanies); - - return getDiscover(discover); - } - - /** - * Discover movies by different types of data like average rating, number of votes, genres and certifications. - * - * @param discover A discover object containing the search criteria required - * @return - * @throws MovieDbException - */ - public TmdbResultsList getDiscover(Discover discover) throws MovieDbException { - ApiUrl apiUrl = new ApiUrl(apiKey, BASE_DISCOVER, "/movie"); - - apiUrl.setArguments(discover.getParams()); - - URL url = apiUrl.buildUrl(); - String webpage = requestWebPage(url); - - try { - WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); - TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); - results.copyWrapper(wrapper); - return results; - } catch (IOException ex) { - LOG.warn("Failed to get discover list: {}", ex.getMessage()); - throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); - } - } - // - - /** - * Use Jackson to convert Map to JSON string. - */ - public static String convertToJson(Map map) throws MovieDbException { - try { - return mapper.writeValueAsString(map); - } catch (JsonProcessingException jpe) { - throw new MovieDbException(MovieDbException.MovieDbExceptionType.MAPPING_FAILED, "JSON conversion failed", jpe); - } - } -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of TheMovieDB API. + * + * TheMovieDB API 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 + * any later version. + * + * TheMovieDB API 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 TheMovieDB API. If not, see . + * + */ +package com.omertron.themoviedbapi; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import static com.omertron.themoviedbapi.tools.ApiUrl.*; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.methods.HttpGet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yamj.api.common.http.CommonHttpClient; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.omertron.themoviedbapi.MovieDbException.MovieDbExceptionType; +import com.omertron.themoviedbapi.model.*; +import com.omertron.themoviedbapi.results.TmdbResultsList; +import com.omertron.themoviedbapi.results.TmdbResultsMap; +import com.omertron.themoviedbapi.tools.ApiUrl; +import com.omertron.themoviedbapi.tools.WebBrowser; +import com.omertron.themoviedbapi.wrapper.*; + +/** + * The MovieDb API

This is for version 3 of the API as specified here: http://help.themoviedb.org/kb/api/about-3 + * + * @author stuart.boston + */ +public class TheMovieDbApi { + + private static final Logger LOG = LoggerFactory.getLogger(TheMovieDbApi.class); + private static final String FAILED_KEYWORD = "Failed to get keyword: {}"; + private String apiKey; + private CommonHttpClient httpClient; + private TmdbConfiguration tmdbConfig; + // API Methods + private static final String BASE_MOVIE = "movie/"; + private static final String BASE_PERSON = "person/"; + private static final String BASE_COMPANY = "company/"; + private static final String BASE_GENRE = "genre/"; + private static final String BASE_AUTH = "authentication/"; + private static final String BASE_COLLECTION = "collection/"; + private static final String BASE_ACCOUNT = "account/"; + private static final String BASE_SEARCH = "search/"; + private static final String BASE_LIST = "list/"; + private static final String BASE_KEYWORD = "keyword/"; + private static final String BASE_JOB = "job/"; + private static final String BASE_DISCOVER = "discover/"; + // Jackson JSON configuration + private static ObjectMapper mapper = new ObjectMapper(); + + /** + * API for The Movie Db. + * + * @param apiKey + * @throws MovieDbException + */ + public TheMovieDbApi(String apiKey) throws MovieDbException { + this(apiKey, null); + } + + /** + * API for The Movie Db. + * + * @param apiKey + * @param httpClient The httpClient to use for web requests. + * @throws MovieDbException + */ + public TheMovieDbApi(String apiKey, CommonHttpClient httpClient) throws MovieDbException { + this.apiKey = apiKey; + this.httpClient = httpClient; + + ApiUrl apiUrl = new ApiUrl(apiKey, "configuration"); + URL configUrl = apiUrl.buildUrl(); + String webpage = requestWebPage(configUrl); + + try { + WrapperConfig wc = mapper.readValue(webpage, WrapperConfig.class); + tmdbConfig = wc.getTmdbConfiguration(); + } catch (IOException ex) { + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, "Failed to read configuration", ex); + } + } + + /** + * Get the API key that is to be used + * + */ + public String getApiKey() { + return apiKey; + } + + private String requestWebPage(URL url) throws MovieDbException { + return requestWebPage(url, null, Boolean.FALSE); + } + + private String requestWebPage(URL url, String jsonBody) throws MovieDbException { + return requestWebPage(url, jsonBody, Boolean.FALSE); + } + + private String requestWebPage(URL url, String jsonBody, boolean isDeleteRequest) throws MovieDbException { + // use HTTP client implementation + if (httpClient != null) { + try { + HttpGet httpGet = new HttpGet(url.toURI()); + httpGet.addHeader("accept", "application/json"); + + if (StringUtils.isNotBlank(jsonBody)) { + // TODO: Add the json body to the request + throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Unable to proces JSON request"); + } + + if (isDeleteRequest) { + //TODO: Handle delete request + throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Unable to proces delete request"); + } + + return httpClient.requestContent(httpGet); + } catch (URISyntaxException ex) { + throw new MovieDbException(MovieDbException.MovieDbExceptionType.CONNECTION_ERROR, null, ex); + } catch (IOException ex) { + throw new MovieDbException(MovieDbException.MovieDbExceptionType.CONNECTION_ERROR, null, ex); + } catch (RuntimeException ex) { + throw new MovieDbException(MovieDbException.MovieDbExceptionType.HTTP_503_ERROR, "Service Unavailable", ex); + } + } + + // use web browser + return WebBrowser.request(url, jsonBody, isDeleteRequest); + } + + /** + * Set the proxy information + * + * @param host + * @param port + * @param username + * @param password + */ + public void setProxy(String host, String port, String username, String password) { + // should be set in HTTP client already + if (httpClient != null) { + return; + } + + WebBrowser.setProxyHost(host); + WebBrowser.setProxyPort(port); + WebBrowser.setProxyUsername(username); + WebBrowser.setProxyPassword(password); + } + + /** + * Set the connection and read time out values + * + * @param connect + * @param read + */ + public void setTimeout(int connect, int read) { + // should be set in HTTP client already + if (httpClient != null) { + return; + } + + WebBrowser.setWebTimeoutConnect(connect); + WebBrowser.setWebTimeoutRead(read); + } + + /** + * Compare the MovieDB object with a title & year + * + * @param moviedb The moviedb object to compare too + * @param title The title of the movie to compare + * @param year The year of the movie to compare exact match + * @return True if there is a match, False otherwise. + */ + public static boolean compareMovies(MovieDb moviedb, String title, String year) { + return compareMovies(moviedb, title, year, 0); + } + + /** + * Compare the MovieDB object with a title & year + * + * @param moviedb The moviedb object to compare too + * @param title The title of the movie to compare + * @param year The year of the movie to compare + * @param maxDistance The Levenshtein Distance between the two titles. 0 = exact match + * @return True if there is a match, False otherwise. + */ + public static boolean compareMovies(MovieDb moviedb, String title, String year, int maxDistance) { + if ((moviedb == null) || (StringUtils.isBlank(title))) { + return Boolean.FALSE; + } + + if (isValidYear(year) && isValidYear(moviedb.getReleaseDate())) { + // Compare with year + String movieYear = moviedb.getReleaseDate().substring(0, 4); + if (movieYear.equals(year)) { + if (compareDistance(moviedb.getOriginalTitle(), title, maxDistance)) { + return Boolean.TRUE; + } + + if (compareDistance(moviedb.getTitle(), title, maxDistance)) { + return Boolean.TRUE; + } + } + } + + // Compare without year + if (compareDistance(moviedb.getOriginalTitle(), title, maxDistance)) { + return Boolean.TRUE; + } + + if (compareDistance(moviedb.getTitle(), title, maxDistance)) { + return Boolean.TRUE; + } + + return Boolean.FALSE; + } + + /** + * Compare the Levenshtein Distance between the two strings + * + * @param title1 + * @param title2 + * @param distance + */ + private static boolean compareDistance(String title1, String title2, int distance) { + return (StringUtils.getLevenshteinDistance(title1, title2) <= distance); + } + + /** + * Check the year is not blank or UNKNOWN + * + * @param year + */ + private static boolean isValidYear(String year) { + return (StringUtils.isNotBlank(year) && !year.equals("UNKNOWN")); + } + + // + /** + * Get the configuration information + */ + public TmdbConfiguration getConfiguration() { + return tmdbConfig; + } + + /** + * Generate the full image URL from the size and image path + * + * @param imagePath + * @param requiredSize + * @throws MovieDbException + */ + public URL createImageUrl(String imagePath, String requiredSize) throws MovieDbException { + if (!tmdbConfig.isValidSize(requiredSize)) { + throw new MovieDbException(MovieDbExceptionType.INVALID_IMAGE, requiredSize); + } + + StringBuilder sb = new StringBuilder(tmdbConfig.getBaseUrl()); + sb.append(requiredSize); + sb.append(imagePath); + try { + return (new URL(sb.toString())); + } catch (MalformedURLException ex) { + LOG.warn("Failed to create image URL: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.INVALID_URL, sb.toString(), ex); + } + } + // + + // + /** + * This method is used to generate a valid request token for user based authentication. + * + * A request token is required in order to request a session id. + * + * You can generate any number of request tokens but they will expire after 60 minutes. + * + * As soon as a valid session id has been created the token will be destroyed. + * + * @throws MovieDbException + */ + public TokenAuthorisation getAuthorisationToken() throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_AUTH, "token/new"); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, TokenAuthorisation.class); + } catch (IOException ex) { + LOG.warn("Failed to get Authorisation Token: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.AUTHORISATION_FAILURE, webpage, ex); + } + } + + /** + * This method is used to generate a session id for user based authentication. + * + * A session id is required in order to use any of the write methods. + * + * @param token + * @throws MovieDbException + */ + public TokenSession getSessionToken(TokenAuthorisation token) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_AUTH, "session/new"); + + if (!token.getSuccess()) { + LOG.warn("Authorisation token was not successful!"); + throw new MovieDbException(MovieDbExceptionType.AUTHORISATION_FAILURE, "Authorisation token was not successful!"); + } + + apiUrl.addArgument(PARAM_TOKEN, token.getRequestToken()); + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, TokenSession.class); + } catch (IOException ex) { + LOG.warn("Failed to get Session Token: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to generate a guest session id. + * + * A guest session can be used to rate movies without having a registered TMDb user account. + * + * You should only generate a single guest session per user (or device) as you will be able to attach the ratings to a TMDb user + * account in the future. + * + * There are also IP limits in place so you should always make sure it's the end user doing the guest session actions. + * + * If a guest session is not used for the first time within 24 hours, it will be automatically discarded. + * + * @throws MovieDbException + */ + public TokenSession getGuestSessionToken() throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_AUTH, "guest_session/new"); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, TokenSession.class); + } catch (IOException ex) { + LOG.warn("Failed to get Session Token: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the basic information for an account. You will need to have a valid session id. + * + * + * @throws MovieDbException + */ + public Account getAccount(String sessionId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT.replace("/", "")); + + apiUrl.addArgument(PARAM_SESSION, sessionId); + + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, Account.class); + } catch (IOException ex) { + LOG.warn("Failed to get Session Token: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + public List getFavoriteMovies(String sessionId, int accountId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/favorite_movies"); + apiUrl.addArgument(PARAM_SESSION, sessionId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, WrapperMovie.class).getMovies(); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + public StatusCode changeFavoriteStatus(String sessionId, int accountId, Integer movieId, boolean isFavorite) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/favorite"); + + apiUrl.addArgument(PARAM_SESSION, sessionId); + + HashMap body = new HashMap(); + body.put("movie_id", movieId); + body.put("favorite", isFavorite); + String jsonBody = convertToJson(body); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url, jsonBody); + + try { + return mapper.readValue(webpage, StatusCode.class); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Add a movie to an account's watch list. + */ + public StatusCode addToWatchList(String sessionId, int accountId, Integer movieId) throws MovieDbException { + return modifyWatchList(sessionId, accountId, movieId, true); + } + + /** + * Remove a movie from an account's watch list. + */ + public StatusCode removeFromWatchList(String sessionId, int accountId, Integer movieId) throws MovieDbException { + return modifyWatchList(sessionId, accountId, movieId, false); + } + + private StatusCode modifyWatchList(String sessionId, int accountId, Integer movieId, boolean add) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/movie_watchlist"); + + apiUrl.addArgument(PARAM_SESSION, sessionId); + + HashMap body = new HashMap(); + body.put("movie_id", movieId); + body.put("movie_watchlist", add); + String jsonBody = convertToJson(body); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url, jsonBody); + + try { + return mapper.readValue(webpage, StatusCode.class); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + // No account functions + // + // + /** + * This method is used to retrieve all of the basic movie information. + * + * It will return the single highest rated poster and backdrop. + * + * @param movieId + * @param language + * @throws MovieDbException + */ + public MovieDb getMovieInfo(int movieId, String language, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE); + + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + try { + return mapper.readValue(webpage, MovieDb.class); + } catch (IOException ex) { + LOG.warn("Failed to get movie info: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve all of the basic movie information. + * + * It will return the single highest rated poster and backdrop. + * + * @param imdbId + * @param language + * @throws MovieDbException + */ + public MovieDb getMovieInfoImdb(String imdbId, String language, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE); + + apiUrl.addArgument(PARAM_ID, imdbId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + try { + return mapper.readValue(webpage, MovieDb.class); + } catch (IOException ex) { + LOG.warn("Failed to get movie info: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve all of the alternative titles we have for a particular movie. + * + * @param movieId + * @param country + * @throws MovieDbException + */ + public TmdbResultsList getMovieAlternativeTitles(int movieId, String country, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/alternative_titles"); + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(country)) { + apiUrl.addArgument(PARAM_COUNTRY, country); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + try { + WrapperAlternativeTitles wrapper = mapper.readValue(webpage, WrapperAlternativeTitles.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getTitles()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie alternative titles: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the cast information for a specific movie id. + * + * TODO: Add a function to enrich the data with the people methods + * + * @param movieId + * @throws MovieDbException + */ + public TmdbResultsList getMovieCasts(int movieId, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/casts"); + apiUrl.addArgument(PARAM_ID, movieId); + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovieCasts wrapper = mapper.readValue(webpage, WrapperMovieCasts.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie casts: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method should be used when you’re wanting to retrieve all of the images for a particular movie. + * + * @param movieId + * @param language + * @throws MovieDbException + */ + public TmdbResultsList getMovieImages(int movieId, String language, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/images"); + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperImages wrapper = mapper.readValue(webpage, WrapperImages.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie images: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve all of the keywords that have been added to a particular movie. + * + * Currently, only English keywords exist. + * + * @param movieId + * @throws MovieDbException + */ + public TmdbResultsList getMovieKeywords(int movieId, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/keywords"); + apiUrl.addArgument(PARAM_ID, movieId); + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovieKeywords wrapper = mapper.readValue(webpage, WrapperMovieKeywords.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getKeywords()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie keywords: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve all of the release and certification data we have for a specific movie. + * + * @param movieId + * @param language + * @throws MovieDbException + */ + public TmdbResultsList getMovieReleaseInfo(int movieId, String language, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/releases"); + apiUrl.addArgument(PARAM_ID, movieId); + apiUrl.addArgument(PARAM_LANGUAGE, language); + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperReleaseInfo wrapper = mapper.readValue(webpage, WrapperReleaseInfo.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getCountries()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie release information: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve all of the trailers for a particular movie. + * + * Supported sites are YouTube and QuickTime. + * + * @param movieId + * @param language + * @throws MovieDbException + */ + public TmdbResultsList getMovieTrailers(int movieId, String language, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/trailers"); + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperTrailers wrapper = mapper.readValue(webpage, WrapperTrailers.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie trailers: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve a list of the available translations for a specific movie. + * + * @param movieId + * @throws MovieDbException + */ + public TmdbResultsList getMovieTranslations(int movieId, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/translations"); + apiUrl.addArgument(PARAM_ID, movieId); + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperTranslations wrapper = mapper.readValue(webpage, WrapperTranslations.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getTranslations()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie tranlations: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * The similar movies method will let you retrieve the similar movies for a particular movie. + * + * This data is created dynamically but with the help of users votes on TMDb. + * + * The data is much better with movies that have more keywords + * + * @param movieId + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList getSimilarMovies(int movieId, String language, int page, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/similar_movies"); + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get similar movies: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + public TmdbResultsList getReviews(int movieId, String language, int page, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/reviews"); + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperReviews wrapper = mapper.readValue(webpage, WrapperReviews.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getReviews()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get reviews: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the lists that the movie belongs to + * + * @param movieId + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList getMovieLists(int movieId, String language, int page, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/lists"); + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovieList wrapper = mapper.readValue(webpage, WrapperMovieList.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovieList()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie lists: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the changes for a specific movie id. + * + * Changes are grouped by key, and ordered by date in descending order. + * + * By default, only the last 24 hours of changes are returned. + * + * The maximum number of days that can be returned in a single request is 14. + * + * The language is present on fields that are translatable. + * + * TODO: DOES NOT WORK AT THE MOMENT. This is due to the "value" item changing type in the ChangeItem + * + * @param movieId + * @param startDate the start date of the changes, optional + * @param endDate the end date of the changes, optional + * @throws MovieDbException + */ + public TmdbResultsMap> getMovieChanges(int movieId, String startDate, String endDate) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/changes"); + apiUrl.addArgument(PARAM_ID, movieId); + + if (StringUtils.isNotBlank(startDate)) { + apiUrl.addArgument(PARAM_START_DATE, startDate); + } + + if (StringUtils.isNotBlank(endDate)) { + apiUrl.addArgument(PARAM_END_DATE, endDate); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + try { + WrapperChanges wrapper = mapper.readValue(webpage, WrapperChanges.class); + + Map> results = new HashMap>(); + for (ChangeKeyItem changeItem : wrapper.getChangedItems()) { + results.put(changeItem.getKey(), changeItem.getChangedItems()); + } + + return new TmdbResultsMap>(results); + } catch (IOException ex) { + LOG.warn("Failed to get movie changes: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + + } + + /** + * This method is used to retrieve the newest movie that was added to TMDb. + * + */ + public MovieDb getLatestMovie() throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/latest"); + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, MovieDb.class); + } catch (IOException ex) { + LOG.warn("Failed to get latest movie: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the list of upcoming movies. + * + * This list refreshes every day. + * + * The maximum number of items this list will include is 100. + * + * @throws MovieDbException + */ + public TmdbResultsList getUpcoming(String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "upcoming"); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get upcoming movies: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + + } + + /** + * This method is used to retrieve the movies currently in theatres. + * + * This is a curated list that will normally contain 100 movies. The default response will return 20 movies. + * + * TODO: Implement more than 20 movies + * + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList getNowPlayingMovies(String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "now-playing"); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get now playing movies: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve the daily movie popularity list. + * + * This list is updated daily. The default response will return 20 movies. + * + * TODO: Implement more than 20 movies + * + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList getPopularMovieList(String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "popular"); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get popular movie list: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve the top rated movies that have over 10 votes on TMDb. + * + * The default response will return 20 movies. + * + * TODO: Implement more than 20 movies + * + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList getTopRatedMovies(String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "top-rated"); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get top rated movies: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + public List getRatedMovies(String sessionId, int accountId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/rated_movies"); + apiUrl.addArgument(PARAM_SESSION, sessionId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, WrapperMovie.class).getMovies(); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method lets users rate a movie. + * + * A valid session id is required. + * + * @param sessionId + * @param movieId + * @param rating + * @throws MovieDbException + */ + public boolean postMovieRating(String sessionId, Integer movieId, Integer rating) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, movieId + "/rating"); + + apiUrl.addArgument(PARAM_SESSION, sessionId); + + if (rating < 0 || rating > 10) { + throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Rating out of range"); + } + + String jsonBody = convertToJson(Collections.singletonMap("value", rating)); + LOG.info("Body: {}", jsonBody); + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url, jsonBody); + + try { + StatusCode status = mapper.readValue(webpage, StatusCode.class); + LOG.info("Status: {}", status); + int code = status.getStatusCode(); + return code == 12; + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * This method is used to retrieve all of the basic information about a movie collection. + * + * You can get the ID needed for this method by making a getMovieInfo request for the belongs_to_collection. + * + * @param collectionId + * @param language + * @throws MovieDbException + */ + public CollectionInfo getCollectionInfo(int collectionId, String language) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COLLECTION); + apiUrl.addArgument(PARAM_ID, collectionId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, CollectionInfo.class); + } catch (IOException ex) { + LOG.warn("Failed to get collection information: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get all of the images for a particular collection by collection id. + * + * @param collectionId + * @param language + * @throws MovieDbException + */ + public TmdbResultsList getCollectionImages(int collectionId, String language) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COLLECTION, "/images"); + apiUrl.addArgument(PARAM_ID, collectionId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperImages wrapper = mapper.readValue(webpage, WrapperImages.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getAll(ArtworkType.POSTER, ArtworkType.BACKDROP)); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get collection images: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * This method is used to retrieve all of the basic person information. + * + * It will return the single highest rated profile image. + * + * @param personId + * @throws MovieDbException + */ + public Person getPersonInfo(int personId, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON); + + apiUrl.addArgument(PARAM_ID, personId); + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, Person.class); + } catch (IOException ex) { + LOG.warn("Failed to get movie info: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve all of the cast & crew information for the person. + * + * It will return the single highest rated poster for each movie record. + * + * @param personId + * @throws MovieDbException + */ + public TmdbResultsList getPersonCredits(int personId, String... appendToResponse) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/credits"); + + apiUrl.addArgument(PARAM_ID, personId); + apiUrl.appendToResponse(appendToResponse); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperPersonCredits wrapper = mapper.readValue(webpage, WrapperPersonCredits.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getAll()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get person credits: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve all of the profile images for a person. + * + * @param personId + * @throws MovieDbException + */ + public TmdbResultsList getPersonImages(int personId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/images"); + + apiUrl.addArgument(PARAM_ID, personId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperImages wrapper = mapper.readValue(webpage, WrapperImages.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getAll(ArtworkType.PROFILE)); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get person images: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the changes for a specific person id. + * + * Changes are grouped by key, and ordered by date in descending order. + * + * By default, only the last 24 hours of changes are returned. + * + * The maximum number of days that can be returned in a single request is 14. + * + * The language is present on fields that are translatable. + * + * @param personId + * @param startDate + * @param endDate + * @throws MovieDbException + */ + public void getPersonChanges(int personId, String startDate, String endDate) throws MovieDbException { + throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Not implemented yet"); + } + + /** + * Get the list of popular people on The Movie Database. + * + * This list refreshes every day. + * + * @return + * @throws MovieDbException + */ + public TmdbResultsList getPersonPopular() throws MovieDbException { + return getPersonPopular(0); + } + + /** + * Get the list of popular people on The Movie Database. + * + * This list refreshes every day. + * + * @param page + * @return + * @throws MovieDbException + */ + public TmdbResultsList getPersonPopular(int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/popular"); + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperPersonList wrapper = mapper.readValue(webpage, WrapperPersonList.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getPersonList()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get person images: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the latest person id. + * + * @throws MovieDbException + */ + public Person getPersonLatest() throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_PERSON, "/latest"); + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, Person.class); + } catch (IOException ex) { + LOG.warn("Failed to get latest person: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * This method is used to retrieve the basic information about a production company on TMDb. + * + * @param companyId + * @throws MovieDbException + */ + public Company getCompanyInfo(int companyId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COMPANY); + + apiUrl.addArgument(PARAM_ID, companyId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, Company.class); + } catch (IOException ex) { + LOG.warn("Failed to get company information: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method is used to retrieve the movies associated with a company. + * + * These movies are returned in order of most recently released to oldest. The default response will return 20 movies per page. + * + * TODO: Implement more than 20 movies + * + * @param companyId + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList getCompanyMovies(int companyId, String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_COMPANY, "/movies"); + + apiUrl.addArgument(PARAM_ID, companyId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperCompanyMovies wrapper = mapper.readValue(webpage, WrapperCompanyMovies.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get company movies: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * You can use this method to retrieve the list of genres used on TMDb. + * + * These IDs will correspond to those found in movie calls. + * + * @param language + */ + public TmdbResultsList getGenreList(String language) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_GENRE, "/list"); + apiUrl.addArgument(PARAM_LANGUAGE, language); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperGenres wrapper = mapper.readValue(webpage, WrapperGenres.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getGenres()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get genre list: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get a list of movies per genre. + * + * It is important to understand that only movies with more than 10 votes get listed. + * + * This prevents movies from 1 10/10 rating from being listed first and for the first 5 pages. + * + * @param genreId + * @param language + * @param page + */ + public TmdbResultsList getGenreMovies(int genreId, String language, int page, boolean includeAllMovies) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_GENRE, "/movies"); + apiUrl.addArgument(PARAM_ID, genreId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + apiUrl.addArgument(PARAM_INCLUDE_ALL_MOVIES, includeAllMovies); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get genre movie list: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * Search Movies This is a good starting point to start finding movies on TMDb. + * + * @param movieName + * @param searchYear Limit the search to the provided year. Zero (0) will get all years + * @param language The language to include. Can be blank/null. + * @param includeAdult true or false to include adult titles in the search + * @param page The page of results to return. 0 to get the default (first page) + * @throws MovieDbException + */ + public TmdbResultsList searchMovie(String movieName, int searchYear, String language, boolean includeAdult, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "movie"); + if (StringUtils.isNotBlank(movieName)) { + apiUrl.addArgument(PARAM_QUERY, movieName); + } + + if (searchYear > 0) { + apiUrl.addArgument(PARAM_YEAR, Integer.toString(searchYear)); + } + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + apiUrl.addArgument(PARAM_ADULT, Boolean.toString(includeAdult)); + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); + } + + URL url = apiUrl.buildUrl(); + + String webpage = requestWebPage(url); + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to find movie: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + + } + + /** + * Search for collections by name. + * + * @param query + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList searchCollection(String query, String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "collections"); + + if (StringUtils.isNotBlank(query)) { + apiUrl.addArgument(PARAM_QUERY, query); + } + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); + } + + URL url = apiUrl.buildUrl(); + + String webpage = requestWebPage(url); + try { + WrapperCollection wrapper = mapper.readValue(webpage, WrapperCollection.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to find collection: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This is a good starting point to start finding people on TMDb. + * + * The idea is to be a quick and light method so you can iterate through people quickly. + * + * @param personName + * @param includeAdult + * @param page + * @throws MovieDbException + */ + public TmdbResultsList searchPeople(String personName, boolean includeAdult, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "person"); + apiUrl.addArgument(PARAM_QUERY, personName); + apiUrl.addArgument(PARAM_ADULT, includeAdult); + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperPerson wrapper = mapper.readValue(webpage, WrapperPerson.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to find person: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Search for lists by name and description. + * + * @param query + * @param language + * @param page + * @throws MovieDbException + */ + public TmdbResultsList searchList(String query, String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "list"); + + if (StringUtils.isNotBlank(query)) { + apiUrl.addArgument(PARAM_QUERY, query); + } + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); + } + + URL url = apiUrl.buildUrl(); + + String webpage = requestWebPage(url); + try { + WrapperMovieList wrapper = mapper.readValue(webpage, WrapperMovieList.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovieList()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to find list: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Search Companies. + * + * You can use this method to search for production companies that are part of TMDb. The company IDs will map to those returned + * on movie calls. + * + * http://help.themoviedb.org/kb/api/search-companies + * + * @param companyName + * @param page + * @throws MovieDbException + */ + public TmdbResultsList searchCompanies(String companyName, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "company"); + apiUrl.addArgument(PARAM_QUERY, companyName); + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + try { + WrapperCompany wrapper = mapper.readValue(webpage, WrapperCompany.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to find company: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Search for keywords by name + * + * @param query + * @param page + * @throws MovieDbException + */ + public TmdbResultsList searchKeyword(String query, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_SEARCH, "keyword"); + + if (StringUtils.isNotBlank(query)) { + apiUrl.addArgument(PARAM_QUERY, query); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, Integer.toString(page)); + } + + URL url = apiUrl.buildUrl(); + + String webpage = requestWebPage(url); + try { + WrapperKeywords wrapper = mapper.readValue(webpage, WrapperKeywords.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to find keyword: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * Get a list by its ID + * + * @param listId + * @return The list and its items + * @throws MovieDbException + */ + public MovieDbList getList(String listId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST); + apiUrl.addArgument(PARAM_ID, listId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, MovieDbList.class); + } catch (IOException ex) { + LOG.warn("Failed to get list: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get all lists of a given user + * + * @return The lists + * @throws MovieDbException + */ + public List getUserLists(String sessionId, int accountID) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountID + "/lists"); + apiUrl.addArgument(PARAM_SESSION, sessionId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, WrapperMovieDbList.class).getLists(); + } catch (IOException ex) { + LOG.warn("Failed to get lists: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method lets users create a new list. A valid session id is required. + * + * @return The list id + * @throws MovieDbException + */ + public String createList(String sessionId, String name, String description) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, "list"); + apiUrl.addArgument(PARAM_SESSION, sessionId); + + HashMap body = new HashMap(); + body.put("name", StringUtils.trimToEmpty(name)); + body.put("description", StringUtils.trimToEmpty(description)); + + String jsonBody = convertToJson(body); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url, jsonBody); + + + try { + return mapper.readValue(webpage, MovieDbListStatus.class).getListId(); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Check to see if a movie ID is already added to a list. + * + * @return true if the movie is on the list + * @throws MovieDbException + */ + public boolean isMovieOnList(String listId, Integer movieId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST, listId + "/item_status"); + apiUrl.addArgument("movie_id", movieId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, ListItemStatus.class).isItemPresent(); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method lets users add new movies to a list that they created. A valid session id is required. + * + * @return true if the movie is on the list + * @throws MovieDbException + */ + public StatusCode addMovieToList(String sessionId, String listId, Integer movieId) throws MovieDbException { + return modifyMovieList(sessionId, listId, movieId, "/add_item"); + } + + /** + * This method lets users remove movies from a list that they created. A valid session id is required. + * + * @return true if the movie is on the list + * @throws MovieDbException + */ + public StatusCode removeMovieFromList(String sessionId, String listId, Integer movieId) throws MovieDbException { + return modifyMovieList(sessionId, listId, movieId, "/remove_item"); + } + + private StatusCode modifyMovieList(String sessionId, String listId, Integer movieId, String operation) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST, listId + operation); + + apiUrl.addArgument(PARAM_SESSION, sessionId); + + String jsonBody = convertToJson(Collections.singletonMap("media_id", movieId + "")); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url, jsonBody); + + try { + return mapper.readValue(webpage, StatusCode.class); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * Get the list of movies on an accounts watchlist. + * + * @return The watchlist of the user + * @throws MovieDbException + */ + public List getWatchList(String sessionId, int accountId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_ACCOUNT, accountId + "/movie_watchlist"); + apiUrl.addArgument(PARAM_SESSION, sessionId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, WrapperMovie.class).getMovies(); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + /** + * This method lets users delete a list that they created. A valid session id is required. + * + * @throws MovieDbException + */ + public StatusCode deleteMovieList(String sessionId, String listId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_LIST, listId); + + apiUrl.addArgument(PARAM_SESSION, sessionId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url, null, true); + + + try { + return mapper.readValue(webpage, StatusCode.class); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * Get the basic information for a specific keyword id. + * + * @param keywordId + * @return + * @throws MovieDbException + */ + public Keyword getKeyword(String keywordId) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_KEYWORD); + apiUrl.addArgument(PARAM_ID, keywordId); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + return mapper.readValue(webpage, Keyword.class); + } catch (IOException ex) { + LOG.warn(FAILED_KEYWORD, ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + + } + + /** + * Get the list of movies for a particular keyword by id. + * + * @param keywordId + * @param language + * @param page + * @return List of movies with the keyword + * @throws MovieDbException + */ + public TmdbResultsList getKeywordMovies(String keywordId, String language, int page) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_KEYWORD, "/movies"); + apiUrl.addArgument(PARAM_ID, keywordId); + + if (StringUtils.isNotBlank(language)) { + apiUrl.addArgument(PARAM_LANGUAGE, language); + } + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperKeywordMovies wrapper = mapper.readValue(webpage, WrapperKeywordMovies.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get top rated movies: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + + } + // + + // + /** + * Get a list of movie ids that have been edited. By default we show the last 24 hours and only 100 items per page. The maximum + * number of days that can be returned in a single request is 14. You can then use the movie changes API to get the actual data + * that has been changed. Please note that the change log system to support this was changed on October 5, 2012 and will only + * show movies that have been edited since. + * + * @param page + * @param startDate the start date of the changes, optional + * @param endDate the end date of the changes, optional + * @return List of changed movie + * @throws MovieDbException + */ + public TmdbResultsList getMovieChangesList(int page, String startDate, String endDate) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_MOVIE, "/changes"); + + if (page > 0) { + apiUrl.addArgument(PARAM_PAGE, page); + } + + if (StringUtils.isNotBlank(startDate)) { + apiUrl.addArgument(PARAM_START_DATE, startDate); + } + + if (StringUtils.isNotBlank(endDate)) { + apiUrl.addArgument(PARAM_END_DATE, endDate); + } + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + try { + WrapperMovieChanges wrapper = mapper.readValue(webpage, WrapperMovieChanges.class); + + TmdbResultsList results = new TmdbResultsList(wrapper.getResults()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get movie changes: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + + public void getPersonChangesList(int page, String startDate, String endDate) throws MovieDbException { + throw new MovieDbException(MovieDbExceptionType.UNKNOWN_CAUSE, "Not implemented yet"); + } + // + + // + public TmdbResultsList getJobs() throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_JOB, "/list"); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperJobList wrapper = mapper.readValue(webpage, WrapperJobList.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getJobs()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get job list: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + // + /** + * Discover movies by different types of data like average rating, number of votes, genres and certifications. + * + * You can alternatively create a "discover" object and pass it to this method to cut out the requirement for all of these + * parameters + * + * @param page Minimum value is 1 + * @param language ISO 639-1 code. + * @param sortBy Available options are vote_average.desc, vote_average.asc, release_date.desc, release_date.asc, + * popularity.desc, popularity.asc + * @param includeAdult Toggle the inclusion of adult titles + * @param year Filter the results release dates to matches that include this value + * @param primaryReleaseYear Filter the results so that only the primary release date year has this value + * @param voteCountGte Only include movies that are equal to, or have a vote count higher than this value + * @param voteAverageGte Only include movies that are equal to, or have a higher average rating than this value + * @param withGenres Only include movies with the specified genres. Expected value is an integer (the id of a genre). Multiple + * values can be specified. Comma separated indicates an 'AND' query, while a pipe (|) separated value indicates an 'OR'. + * @param releaseDateGte The minimum release to include. Expected format is YYYY-MM-DD + * @param releaseDateLte The maximum release to include. Expected format is YYYY-MM-DD + * @param certificationCountry Only include movies with certifications for a specific country. When this value is specified, + * 'certificationLte' is required. A ISO 3166-1 is expected. + * @param certificationLte Only include movies with this certification and lower. Expected value is a valid certification for + * the specified 'certificationCountry'. + * @param withCompanies Filter movies to include a specific company. Expected value is an integer (the id of a company). They + * can be comma separated to indicate an 'AND' query. + * @return + * @throws MovieDbException + */ + public TmdbResultsList getDiscover(int page, String language, String sortBy, boolean includeAdult, int year, + int primaryReleaseYear, int voteCountGte, float voteAverageGte, String withGenres, String releaseDateGte, + String releaseDateLte, String certificationCountry, String certificationLte, String withCompanies) throws MovieDbException { + + Discover discover = new Discover(); + discover.page(page) + .language(language) + .sortBy(sortBy) + .includeAdult(includeAdult) + .year(year) + .primaryReleaseYear(primaryReleaseYear) + .voteCountGte(voteCountGte) + .voteAverageGte(voteAverageGte) + .withGenres(withGenres) + .releaseDateGte(releaseDateGte) + .releaseDateLte(releaseDateLte) + .certificationCountry(certificationCountry) + .certificationLte(certificationLte) + .withCompanies(withCompanies); + + return getDiscover(discover); + } + + /** + * Discover movies by different types of data like average rating, number of votes, genres and certifications. + * + * @param discover A discover object containing the search criteria required + * @return + * @throws MovieDbException + */ + public TmdbResultsList getDiscover(Discover discover) throws MovieDbException { + ApiUrl apiUrl = new ApiUrl(apiKey, BASE_DISCOVER, "/movie"); + + apiUrl.setArguments(discover.getParams()); + + URL url = apiUrl.buildUrl(); + String webpage = requestWebPage(url); + + try { + WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class); + TmdbResultsList results = new TmdbResultsList(wrapper.getMovies()); + results.copyWrapper(wrapper); + return results; + } catch (IOException ex) { + LOG.warn("Failed to get discover list: {}", ex.getMessage()); + throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex); + } + } + // + + /** + * Use Jackson to convert Map to JSON string. + */ + public static String convertToJson(Map map) throws MovieDbException { + try { + return mapper.writeValueAsString(map); + } catch (JsonProcessingException jpe) { + throw new MovieDbException(MovieDbException.MovieDbExceptionType.MAPPING_FAILED, "JSON conversion failed", jpe); + } + } +} diff --git a/src/main/java/com/omertron/themoviedbapi/model/ArtworkType.java b/src/main/java/com/omertron/themoviedbapi/model/ArtworkType.java index 383c35a33..0ff2190c5 100644 --- a/src/main/java/com/omertron/themoviedbapi/model/ArtworkType.java +++ b/src/main/java/com/omertron/themoviedbapi/model/ArtworkType.java @@ -1,30 +1,30 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of TheMovieDB API. - * - * TheMovieDB API 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 - * any later version. - * - * TheMovieDB API 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 TheMovieDB API. If not, see . - * - */ -package com.omertron.themoviedbapi.model; - -/** - * ArtworkType enum List of the artwork types that are available - */ -public enum ArtworkType { - - POSTER, // Poster artwork - BACKDROP, // Fanart/backdrop - PROFILE // Person image -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of TheMovieDB API. + * + * TheMovieDB API 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 + * any later version. + * + * TheMovieDB API 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 TheMovieDB API. If not, see . + * + */ +package com.omertron.themoviedbapi.model; + +/** + * ArtworkType enum List of the artwork types that are available + */ +public enum ArtworkType { + + POSTER, // Poster artwork + BACKDROP, // Fanart/backdrop + PROFILE // Person image +} diff --git a/src/main/java/com/omertron/themoviedbapi/model/PersonType.java b/src/main/java/com/omertron/themoviedbapi/model/PersonType.java index 3256eb3f0..f1aea34d8 100644 --- a/src/main/java/com/omertron/themoviedbapi/model/PersonType.java +++ b/src/main/java/com/omertron/themoviedbapi/model/PersonType.java @@ -1,30 +1,30 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of TheMovieDB API. - * - * TheMovieDB API 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 - * any later version. - * - * TheMovieDB API 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 TheMovieDB API. If not, see . - * - */ -package com.omertron.themoviedbapi.model; - -/** - * @author stuart.boston - */ -public enum PersonType { - - CAST, // A member of the cast - CREW, // A member of the crew - PERSON // No specific type -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of TheMovieDB API. + * + * TheMovieDB API 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 + * any later version. + * + * TheMovieDB API 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 TheMovieDB API. If not, see . + * + */ +package com.omertron.themoviedbapi.model; + +/** + * @author stuart.boston + */ +public enum PersonType { + + CAST, // A member of the cast + CREW, // A member of the crew + PERSON // No specific type +} diff --git a/src/main/java/com/omertron/themoviedbapi/results/TmdbResultsList.java b/src/main/java/com/omertron/themoviedbapi/results/TmdbResultsList.java index 9bf11b531..8242095ba 100644 --- a/src/main/java/com/omertron/themoviedbapi/results/TmdbResultsList.java +++ b/src/main/java/com/omertron/themoviedbapi/results/TmdbResultsList.java @@ -1,50 +1,50 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of TheMovieDB API. - * - * TheMovieDB API 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 - * any later version. - * - * TheMovieDB API 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 TheMovieDB API. If not, see . - * - */ -package com.omertron.themoviedbapi.results; - -import java.util.ArrayList; -import java.util.List; - -/** - * List of the results from TheMovieDb - * - * @author Stuart - * @param - */ -public final class TmdbResultsList extends TmdbResults { - - private List results; - - public TmdbResultsList(List resultList) { - if (resultList != null) { - results = new ArrayList(resultList); - } else { - results = new ArrayList(0); - } - } - - public List getResults() { - return results; - } - - public void setResults(List results) { - this.results = results; - } -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of TheMovieDB API. + * + * TheMovieDB API 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 + * any later version. + * + * TheMovieDB API 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 TheMovieDB API. If not, see . + * + */ +package com.omertron.themoviedbapi.results; + +import java.util.ArrayList; +import java.util.List; + +/** + * List of the results from TheMovieDb + * + * @author Stuart + * @param + */ +public final class TmdbResultsList extends TmdbResults { + + private List results; + + public TmdbResultsList(List resultList) { + if (resultList != null) { + results = new ArrayList(resultList); + } else { + results = new ArrayList(0); + } + } + + public List getResults() { + return results; + } + + public void setResults(List results) { + this.results = results; + } +} diff --git a/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java b/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java index 093996a1a..2836e66b9 100644 --- a/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java +++ b/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java @@ -1,253 +1,253 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of TheMovieDB API. - * - * TheMovieDB API 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 - * any later version. - * - * TheMovieDB API 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 TheMovieDB API. If not, see . - * - */ -package com.omertron.themoviedbapi.tools; - -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; -import java.util.HashMap; -import java.util.Map; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The API URL that is used to construct the API call - * - * @author Stuart - */ -public class ApiUrl { - - /* - * Logger - */ - private static final Logger LOG = LoggerFactory.getLogger(ApiUrl.class); - /* - * TheMovieDbApi API Base URL - */ - private static final String TMDB_API_BASE = "http://api.themoviedb.org/3/"; - /* - * Parameter configuration - */ - private static final String DELIMITER_FIRST = "?"; - private static final String DELIMITER_SUBSEQUENT = "&"; - private static final String DEFAULT_STRING = ""; - /* - * Properties - */ - private String apiKey; - private String method; - private String submethod; - private Map arguments = new HashMap(); - /* - * API Parameters - */ - public static final String PARAM_ADULT = "include_adult="; - public static final String PARAM_API_KEY = "api_key="; - public static final String PARAM_COUNTRY = "country="; - public static final String PARAM_FAVORITE = "favorite="; - public static final String PARAM_ID = "id="; - public static final String PARAM_LANGUAGE = "language="; - public static final String PARAM_INCLUDE_ALL_MOVIES = "include_all_movies="; - public static final String PARAM_MOVIE_WATCHLIST = "movie_watchlist="; - public static final String PARAM_PAGE = "page="; - public static final String PARAM_QUERY = "query="; - public static final String PARAM_SESSION = "session_id="; - public static final String PARAM_TOKEN = "request_token="; - public static final String PARAM_VALUE = "value="; - public static final String PARAM_YEAR = "year="; - public static final String PARAM_START_DATE="start_date="; - public static final String PARAM_END_DATE="end_date="; - private static final String APPEND_TO_RESPONSE = "append_to_response="; - - // - /** - * Constructor for the simple API URL method without a sub-method - * - * @param method - */ - public ApiUrl(String apiKey, String method) { - this.apiKey = apiKey; - this.method = method; - this.submethod = DEFAULT_STRING; - } - - /** - * Constructor for the API URL with a sub-method - * - * @param method - * @param submethod - */ - public ApiUrl(String apiKey, String method, String submethod) { - this.apiKey = apiKey; - this.method = method; - this.submethod = submethod; - } - // - - /** - * Build the URL from the pre-created arguments. - */ - public URL buildUrl() { - StringBuilder urlString = new StringBuilder(TMDB_API_BASE); - - // Get the start of the URL - urlString.append(method); - - // We have either a queury, or a direct request - if (arguments.containsKey(PARAM_QUERY)) { - // Append the suffix of the API URL - if(StringUtils.endsWith(urlString, "/") && submethod.startsWith("/")) { - urlString.deleteCharAt(urlString.length()-1); - } - urlString.append(submethod); - - // Append the key information - urlString.append(DELIMITER_FIRST).append(PARAM_API_KEY); - urlString.append(apiKey); - - // Append the search term - urlString.append(DELIMITER_SUBSEQUENT); - urlString.append(PARAM_QUERY); - - String query = arguments.get(PARAM_QUERY); - - try { - urlString.append(URLEncoder.encode(query, "UTF-8")); - } catch (UnsupportedEncodingException ex) { - LOG.trace("Unable to encode query: '{}' trying raw.", query); - // If we can't encode it, try it raw - urlString.append(query); - } - - // Remove the query from the arguments so it is not added later - arguments.remove(PARAM_QUERY); - } else { - // Append the ID if provided - if (arguments.containsKey(PARAM_ID)) { - urlString.append(arguments.get(PARAM_ID)); - arguments.remove(PARAM_ID); - } - - // Append the suffix of the API URL - if(StringUtils.endsWith(urlString, "/") && submethod.startsWith("/")) { - urlString.deleteCharAt(urlString.length()-1); - } - urlString.append(submethod); - - // Append the key information - urlString.append(DELIMITER_FIRST).append(PARAM_API_KEY); - urlString.append(apiKey); - } - - for (Map.Entry argEntry : arguments.entrySet()) { - urlString.append(DELIMITER_SUBSEQUENT).append(argEntry.getKey()); - urlString.append(argEntry.getValue()); - } - - try { - LOG.trace("URL: {}", urlString.toString()); - return new URL(urlString.toString()); - } catch (MalformedURLException ex) { - LOG.warn("Failed to create URL {} - {}", urlString.toString(), ex.toString()); - return null; - } finally { - arguments.clear(); - } - } - - /** - * Add arguments individually - * - * @param key - * @param value - */ - public void addArgument(String key, String value) { - arguments.put(key, value); - } - - /** - * Add arguments individually - * - * @param key - * @param value - */ - public void addArgument(String key, int value) { - arguments.put(key, Integer.toString(value)); - } - - /** - * Add arguments individually - * - * @param key - * @param value - */ - public void addArgument(String key, boolean value) { - arguments.put(key, Boolean.toString(value)); - } - - /** - * Add arguments individually - * - * @param key - * @param value - */ - public void addArgument(String key, float value) { - arguments.put(key, Float.toString(value)); - } - - /** - * Clear the arguments - */ - public void clearArguments() { - arguments.clear(); - } - - /** - * Set the arguments directly - * - * @param args - */ - public void setArguments(Map args) { - arguments.putAll(args); - } - - /** - * Append any optional parameters to the URL - * - * @param appendToResponse - */ - public void appendToResponse(String[] appendToResponse) { - if (appendToResponse.length > 0) { - StringBuilder sb = new StringBuilder(); - boolean first = Boolean.TRUE; - for (String append : appendToResponse) { - if (first) { - first = Boolean.FALSE; - } else { - sb.append(","); - } - sb.append(append); - } - addArgument(APPEND_TO_RESPONSE, sb.toString()); - } - } -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of TheMovieDB API. + * + * TheMovieDB API 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 + * any later version. + * + * TheMovieDB API 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 TheMovieDB API. If not, see . + * + */ +package com.omertron.themoviedbapi.tools; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The API URL that is used to construct the API call + * + * @author Stuart + */ +public class ApiUrl { + + /* + * Logger + */ + private static final Logger LOG = LoggerFactory.getLogger(ApiUrl.class); + /* + * TheMovieDbApi API Base URL + */ + private static final String TMDB_API_BASE = "http://api.themoviedb.org/3/"; + /* + * Parameter configuration + */ + private static final String DELIMITER_FIRST = "?"; + private static final String DELIMITER_SUBSEQUENT = "&"; + private static final String DEFAULT_STRING = ""; + /* + * Properties + */ + private String apiKey; + private String method; + private String submethod; + private Map arguments = new HashMap(); + /* + * API Parameters + */ + public static final String PARAM_ADULT = "include_adult="; + public static final String PARAM_API_KEY = "api_key="; + public static final String PARAM_COUNTRY = "country="; + public static final String PARAM_FAVORITE = "favorite="; + public static final String PARAM_ID = "id="; + public static final String PARAM_LANGUAGE = "language="; + public static final String PARAM_INCLUDE_ALL_MOVIES = "include_all_movies="; + public static final String PARAM_MOVIE_WATCHLIST = "movie_watchlist="; + public static final String PARAM_PAGE = "page="; + public static final String PARAM_QUERY = "query="; + public static final String PARAM_SESSION = "session_id="; + public static final String PARAM_TOKEN = "request_token="; + public static final String PARAM_VALUE = "value="; + public static final String PARAM_YEAR = "year="; + public static final String PARAM_START_DATE="start_date="; + public static final String PARAM_END_DATE="end_date="; + private static final String APPEND_TO_RESPONSE = "append_to_response="; + + // + /** + * Constructor for the simple API URL method without a sub-method + * + * @param method + */ + public ApiUrl(String apiKey, String method) { + this.apiKey = apiKey; + this.method = method; + this.submethod = DEFAULT_STRING; + } + + /** + * Constructor for the API URL with a sub-method + * + * @param method + * @param submethod + */ + public ApiUrl(String apiKey, String method, String submethod) { + this.apiKey = apiKey; + this.method = method; + this.submethod = submethod; + } + // + + /** + * Build the URL from the pre-created arguments. + */ + public URL buildUrl() { + StringBuilder urlString = new StringBuilder(TMDB_API_BASE); + + // Get the start of the URL + urlString.append(method); + + // We have either a queury, or a direct request + if (arguments.containsKey(PARAM_QUERY)) { + // Append the suffix of the API URL + if(StringUtils.endsWith(urlString, "/") && submethod.startsWith("/")) { + urlString.deleteCharAt(urlString.length()-1); + } + urlString.append(submethod); + + // Append the key information + urlString.append(DELIMITER_FIRST).append(PARAM_API_KEY); + urlString.append(apiKey); + + // Append the search term + urlString.append(DELIMITER_SUBSEQUENT); + urlString.append(PARAM_QUERY); + + String query = arguments.get(PARAM_QUERY); + + try { + urlString.append(URLEncoder.encode(query, "UTF-8")); + } catch (UnsupportedEncodingException ex) { + LOG.trace("Unable to encode query: '{}' trying raw.", query); + // If we can't encode it, try it raw + urlString.append(query); + } + + // Remove the query from the arguments so it is not added later + arguments.remove(PARAM_QUERY); + } else { + // Append the ID if provided + if (arguments.containsKey(PARAM_ID)) { + urlString.append(arguments.get(PARAM_ID)); + arguments.remove(PARAM_ID); + } + + // Append the suffix of the API URL + if(StringUtils.endsWith(urlString, "/") && submethod.startsWith("/")) { + urlString.deleteCharAt(urlString.length()-1); + } + urlString.append(submethod); + + // Append the key information + urlString.append(DELIMITER_FIRST).append(PARAM_API_KEY); + urlString.append(apiKey); + } + + for (Map.Entry argEntry : arguments.entrySet()) { + urlString.append(DELIMITER_SUBSEQUENT).append(argEntry.getKey()); + urlString.append(argEntry.getValue()); + } + + try { + LOG.trace("URL: {}", urlString.toString()); + return new URL(urlString.toString()); + } catch (MalformedURLException ex) { + LOG.warn("Failed to create URL {} - {}", urlString.toString(), ex.toString()); + return null; + } finally { + arguments.clear(); + } + } + + /** + * Add arguments individually + * + * @param key + * @param value + */ + public void addArgument(String key, String value) { + arguments.put(key, value); + } + + /** + * Add arguments individually + * + * @param key + * @param value + */ + public void addArgument(String key, int value) { + arguments.put(key, Integer.toString(value)); + } + + /** + * Add arguments individually + * + * @param key + * @param value + */ + public void addArgument(String key, boolean value) { + arguments.put(key, Boolean.toString(value)); + } + + /** + * Add arguments individually + * + * @param key + * @param value + */ + public void addArgument(String key, float value) { + arguments.put(key, Float.toString(value)); + } + + /** + * Clear the arguments + */ + public void clearArguments() { + arguments.clear(); + } + + /** + * Set the arguments directly + * + * @param args + */ + public void setArguments(Map args) { + arguments.putAll(args); + } + + /** + * Append any optional parameters to the URL + * + * @param appendToResponse + */ + public void appendToResponse(String[] appendToResponse) { + if (appendToResponse.length > 0) { + StringBuilder sb = new StringBuilder(); + boolean first = Boolean.TRUE; + for (String append : appendToResponse) { + if (first) { + first = Boolean.FALSE; + } else { + sb.append(","); + } + sb.append(append); + } + addArgument(APPEND_TO_RESPONSE, sb.toString()); + } + } +} diff --git a/src/main/java/com/omertron/themoviedbapi/wrapper/AbstractWrapperId.java b/src/main/java/com/omertron/themoviedbapi/wrapper/AbstractWrapperId.java index 7c2485fb1..872ab2e8d 100644 --- a/src/main/java/com/omertron/themoviedbapi/wrapper/AbstractWrapperId.java +++ b/src/main/java/com/omertron/themoviedbapi/wrapper/AbstractWrapperId.java @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of TheMovieDB API. - * - * TheMovieDB API 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 - * any later version. - * - * TheMovieDB API 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 TheMovieDB API. If not, see . - * - */ -package com.omertron.themoviedbapi.wrapper; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Base class for the wrappers - * - * @author Stuart - */ -public class AbstractWrapperId extends AbstractWrapper implements IWrapperId { - - private static final long serialVersionUID = 1L; - @JsonProperty("id") - private int id; - - @Override - public int getId() { - return id; - } - - @Override - public void setId(int id) { - this.id = id; - } -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of TheMovieDB API. + * + * TheMovieDB API 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 + * any later version. + * + * TheMovieDB API 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 TheMovieDB API. If not, see . + * + */ +package com.omertron.themoviedbapi.wrapper; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Base class for the wrappers + * + * @author Stuart + */ +public class AbstractWrapperId extends AbstractWrapper implements IWrapperId { + + private static final long serialVersionUID = 1L; + @JsonProperty("id") + private int id; + + @Override + public int getId() { + return id; + } + + @Override + public void setId(int id) { + this.id = id; + } +} diff --git a/src/test/java/com/omertron/themoviedbapi/TestLogger.java b/src/test/java/com/omertron/themoviedbapi/TestLogger.java index bd7a4cc5e..8e074a1f0 100644 --- a/src/test/java/com/omertron/themoviedbapi/TestLogger.java +++ b/src/test/java/com/omertron/themoviedbapi/TestLogger.java @@ -1,72 +1,72 @@ -/* - * Copyright (c) 2004-2013 Stuart Boston - * - * This file is part of the FanartTV API. - * - * The FanartTV API 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 - * any later version. - * - * The FanartTV API 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 the FanartTV API. If not, see . - * - */ -package com.omertron.themoviedbapi; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.LogManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TestLogger { - - private static final Logger LOG = LoggerFactory.getLogger(TestLogger.class); - private static final String CRLF = "\n"; - - private TestLogger() { - throw new UnsupportedOperationException("Class can not be instantiated"); - } - - /** - * Configure the logger with a simple in-memory file for the required log level - * - * @param level The logging level required - * @return True if successful - */ - public static boolean Configure(String level) { - StringBuilder config = new StringBuilder("handlers = java.util.logging.ConsoleHandler\n"); - config.append(".level = ").append(level).append(CRLF); - config.append("java.util.logging.ConsoleHandler.level = ").append(level).append(CRLF); - // Only works with Java 7 or later - config.append("java.util.logging.SimpleFormatter.format = [%1$tc %4$s] %2$s - %5$s %6$s%n").append(CRLF); - // Exclude http logging - config.append("sun.net.www.protocol.http.HttpURLConnection.level = OFF").append(CRLF); - - InputStream ins = new ByteArrayInputStream(config.toString().getBytes()); - try { - LogManager.getLogManager().readConfiguration(ins); - } catch (IOException e) { - LOG.warn("Failed to configure log manager due to an IO problem", e); - return Boolean.FALSE; - } - LOG.debug("Logger initialized to '{}' level", level); - return Boolean.TRUE; - } - - /** - * Set the logging level to "ALL" - * - * @return True if successful - */ - public static boolean Configure() { - return Configure("ALL"); - } -} +/* + * Copyright (c) 2004-2013 Stuart Boston + * + * This file is part of the FanartTV API. + * + * The FanartTV API 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 + * any later version. + * + * The FanartTV API 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 the FanartTV API. If not, see . + * + */ +package com.omertron.themoviedbapi; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.LogManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestLogger { + + private static final Logger LOG = LoggerFactory.getLogger(TestLogger.class); + private static final String CRLF = "\n"; + + private TestLogger() { + throw new UnsupportedOperationException("Class can not be instantiated"); + } + + /** + * Configure the logger with a simple in-memory file for the required log level + * + * @param level The logging level required + * @return True if successful + */ + public static boolean Configure(String level) { + StringBuilder config = new StringBuilder("handlers = java.util.logging.ConsoleHandler\n"); + config.append(".level = ").append(level).append(CRLF); + config.append("java.util.logging.ConsoleHandler.level = ").append(level).append(CRLF); + // Only works with Java 7 or later + config.append("java.util.logging.SimpleFormatter.format = [%1$tc %4$s] %2$s - %5$s %6$s%n").append(CRLF); + // Exclude http logging + config.append("sun.net.www.protocol.http.HttpURLConnection.level = OFF").append(CRLF); + + InputStream ins = new ByteArrayInputStream(config.toString().getBytes()); + try { + LogManager.getLogManager().readConfiguration(ins); + } catch (IOException e) { + LOG.warn("Failed to configure log manager due to an IO problem", e); + return Boolean.FALSE; + } + LOG.debug("Logger initialized to '{}' level", level); + return Boolean.TRUE; + } + + /** + * Set the logging level to "ALL" + * + * @return True if successful + */ + public static boolean Configure() { + return Configure("ALL"); + } +}