|
| 1 | +# thetvdb-java-api |
| 2 | +[](https://opensource.org/licenses/Apache-2.0) |
| 3 | + |
| 4 | +A simple connector for an easy integration of the [TheTVDB.com](https://thetvdb.com/) RESTful API in Java projects. |
| 5 | + |
| 6 | +## Table of contents |
| 7 | +- [Introduction](#introduction) |
| 8 | +- [Technologies](#technologies) |
| 9 | +- [Features](#features) |
| 10 | +- [Setup](#setup) |
| 11 | +- [Code Examples](#code-examples) |
| 12 | +- [Development](#development) |
| 13 | +- [Status](#status) |
| 14 | +- [License](#license) |
| 15 | + |
| 16 | +## Introduction |
| 17 | +With more than [240,000+](https://www.thetvdb.com/about) TV Series and movies _TheTVDB.com_ is probably one of the largest |
| 18 | +digital media metadata databases in the world. Moreover, they offer the opportunity to access this vast amount of data |
| 19 | +on M2M-level by providing a RESTful API, which I think is pretty cool as it enables developers to virtually include |
| 20 | +all this data into their own applications. However, the majority of these applications will probably intend to actually |
| 21 | +make some good use of this information in order to create something beneficial for the end user. Talking about Java |
| 22 | +applications, that's where this connector might come in handy. |
| 23 | + |
| 24 | +One of the main objectives of this little project was to keep the code of these aforementioned applications clean. |
| 25 | +Communicating with the _TheTVDB.com_ API to gather information is a necessity, but most likely not the end of whatever |
| 26 | +you're aiming to create. So in order to not bloat the code with opening connections, preparing requests, process and |
| 27 | +evaluate responses and finally parse its JSON content, all of this may be handled by the `thetvdb-java-api` connector, |
| 28 | +leaving you with only a few (but unavoidable) lines of code describing what you actually want to achieve (e.g. query |
| 29 | +a TV Series by name). |
| 30 | + |
| 31 | +However, where there is light there is also shadow, they say. Simplifying things often means to also restrict their |
| 32 | +functionality to only some basics. And although this might be quite an acceptable trade-off for many people, there will |
| 33 | +always be someone who is ruled out from using certain tools due to the need of some more advanced functionality. So another |
| 34 | +important goal was to promote this simplified usage while maintaining the usability for more complex use-cases at the |
| 35 | +same time. So it's actually up to the developer whether to query by some common parameters in just a one-liner and to |
| 36 | +work with the prefabbed Java DTOs or to run more complex queries by providing a set of parameters and maybe even parse |
| 37 | +the raw JSON content returned by the _TheTVDB.com_ API all by yourself. Your decision! |
| 38 | + |
| 39 | +## Technologies |
| 40 | +* [Java](https://jdk.java.net/) (1.9) - Class-based, object-oriented programming language |
| 41 | +* [Apache Maven](https://maven.apache.org/download.cgi) (3.6.0) - Software project management and comprehension tool |
| 42 | + |
| 43 | +## Features |
| 44 | +In general, this connector is fully compatible with all available _TheTVDB.com_ API endpoints. However, as new versions |
| 45 | +of the RESTful API might not always be backwards compatible, each major `thetvdb-java-api` release is invariantly linked |
| 46 | +to a specific version of the _TheTVDB.com_ remote API. The API version a specific connector release is using can be derived |
| 47 | +from its version number. For example, `v3.x` uses the _TheTVDB.com_ APIv3 whereas the (not yet existent) `v4.x` would use |
| 48 | +the upcoming APIv4. |
| 49 | + |
| 50 | +<details><summary>Supported _TheTVDB.com_ APIv3 routes (`thetvdb-java-api v3.x`)</summary> |
| 51 | +- Authentication |
| 52 | + + [/login](https://api.thetvdb.com/swagger#!/Authentication/post_login) |
| 53 | + + [/refresh_token](https://api.thetvdb.com/swagger#!/Authentication/get_refresh_token) |
| 54 | +- Episodes |
| 55 | + + [/episodes/{id}](https://api.thetvdb.com/swagger#!/Episodes/get_episodes_id) |
| 56 | +- Languages |
| 57 | + + [/languages](https://api.thetvdb.com/swagger#!/Languages/get_languages) |
| 58 | + + [/languages/{id}](https://api.thetvdb.com/swagger#!/Languages/get_languages_id) |
| 59 | +- Movies |
| 60 | + + [/movies/{id}](https://api.thetvdb.com/swagger#!/Movies/get_movies_id) |
| 61 | + + [/movieupdates](https://api.thetvdb.com/swagger#!/Movies/get_movieupdates) |
| 62 | +- Search |
| 63 | + + [/search/series](https://api.thetvdb.com/swagger#!/Search/get_search_series) |
| 64 | + + [/search/series/params](https://api.thetvdb.com/swagger#!/Search/get_search_series_params) |
| 65 | +- Series |
| 66 | + + [/series/{id}](https://api.thetvdb.com/swagger#!/Series/get_series_id) |
| 67 | + + [/series/{id}](https://api.thetvdb.com/swagger#!/Series/head_series_id) (HEAD) |
| 68 | + + [/series/{id}/actors](https://api.thetvdb.com/swagger#!/Series/get_series_id_actors) |
| 69 | + + [/series/{id}/episodes](https://api.thetvdb.com/swagger#!/Series/get_series_id_episodes) |
| 70 | + + [/series/{id}/episodes/query](https://api.thetvdb.com/swagger#!/Series/get_series_id_episodes_query) |
| 71 | + + [/series/{id}/episodes/query/params](https://api.thetvdb.com/swagger#!/Series/get_series_id_episodes_query_params) |
| 72 | + + [/series/{id}/episodes/summary](https://api.thetvdb.com/swagger#!/Series/get_series_id_episodes_summary) |
| 73 | + + [/series/{id}/filter](https://api.thetvdb.com/swagger#!/Series/get_series_id_filter) |
| 74 | + + [/series/{id}/filter/params](https://api.thetvdb.com/swagger#!/Series/get_series_id_filter_params) |
| 75 | + + [/series/{id}/images](https://api.thetvdb.com/swagger#!/Series/get_series_id_images) |
| 76 | + + [/series/{id}/images/query](https://api.thetvdb.com/swagger#!/Series/get_series_id_images_query) |
| 77 | + + [/series/{id}/images/query/params](https://api.thetvdb.com/swagger#!/Series/get_series_id_images_query_params) |
| 78 | +- Updates |
| 79 | + + [/updated/query](https://api.thetvdb.com/swagger#!/Updates/get_updated_query) |
| 80 | + + [/updated/query/params](https://api.thetvdb.com/swagger#!/Updates/get_updated_query_params) |
| 81 | +- Users |
| 82 | + + [/user](https://api.thetvdb.com/swagger#!/Users/get_user) |
| 83 | + + [/user/favorites](https://api.thetvdb.com/swagger#!/Users/get_user_favorites) |
| 84 | + + [/user/favorites/{id}](https://api.thetvdb.com/swagger#!/Users/delete_user_favorites_id) (DELETE) |
| 85 | + + [/user/favorites/{id}](https://api.thetvdb.com/swagger#!/Users/put_user_favorites_id) (PUT) |
| 86 | + + [/user/ratings](https://api.thetvdb.com/swagger#!/Users/get_user_ratings) |
| 87 | + + [/user/ratings/query](https://api.thetvdb.com/swagger#!/Users/get_user_ratings_query) |
| 88 | + + [/user/ratings/query/params](https://api.thetvdb.com/swagger#!/Users/get_user_ratings_query_params) |
| 89 | + + [/user/ratings/{itemType}/{itemId}](https://api.thetvdb.com/swagger#!/Users/delete_user_ratings_itemType_itemId) |
| 90 | + + [/user/ratings/{itemType}/{itemId}/{itemRating}](https://api.thetvdb.com/swagger#!/Users/put_user_ratings_itemType_itemId_itemRating) |
| 91 | +</details> |
| 92 | + |
| 93 | +## Setup |
| 94 | +#### Maven |
| 95 | +The artifact is *not* available through the central maven repository, but you may still include the connector into your |
| 96 | +maven project via the [jitpack.io](https://jitpack.io/) repository. |
| 97 | + |
| 98 | +1. Add the JitPack repository to your build file |
| 99 | + ```xml |
| 100 | + <repositories> |
| 101 | + <repository> |
| 102 | + <id>jitpack.io</id> |
| 103 | + <url>https://jitpack.io</url> |
| 104 | + </repository> |
| 105 | + </repositories> |
| 106 | + ``` |
| 107 | +2. Add the dependency |
| 108 | + ```xml |
| 109 | + <dependency> |
| 110 | + <groupId>com.github.m0nk3y2k4</groupId> |
| 111 | + <artifactId>thetvdb-java-api</artifactId> |
| 112 | + <version>3.0.0</version> |
| 113 | + </dependency> |
| 114 | + ``` |
| 115 | + |
| 116 | +#### Other build automation tools |
| 117 | +For other tools like e.g. _gradle_ please check out the documentation at https://jitpack.io/. |
| 118 | + |
| 119 | +#### Manually include artifact |
| 120 | +In case your build tool isn't supported, or you're not using any build framework at all you can still include the artifact |
| 121 | +manually as _.jar_ file. The files (with and without dependencies) can either be obtained from the assets section of the |
| 122 | +corresponding [release](https://github.com/m0nk3y2k4/thetvdb-java-api/releases) or by cloning the repository and building |
| 123 | +the artifacts locally: |
| 124 | +```shell script |
| 125 | +mvn clean install |
| 126 | +``` |
| 127 | + |
| 128 | +## Code Examples |
| 129 | +#### Basics |
| 130 | +When it comes to using the connector, there's only one entry point where all your activities start: |
| 131 | +``` |
| 132 | +com.github.m0nk3y2k4.thetvdb.TheTVDBApiFactory |
| 133 | +``` |
| 134 | +This class provides factory methods to create all the objects needed for working with the connector, including new API |
| 135 | +instances, free configurable query parameters and proxies. |
| 136 | + |
| 137 | +So let's create a new API instance using the factory methods. |
| 138 | +```java |
| 139 | + // "Simple" authentication with API-Key only |
| 140 | + TheTVDBApi api = TheTVDBApiFactory.createApi("API_KEY"); |
| 141 | + |
| 142 | + // or... |
| 143 | + |
| 144 | + // "Advanced" authentication with API-Key, user key and user name |
| 145 | + TheTVDBApi usersApi = TheTVDBApiFactory.createApi("API_KEY", "Userkey", "Username"); |
| 146 | +``` |
| 147 | +>Please keep in mind that the _username_ and _key_ are **ONLY** required for the [/user](https://api.thetvdb.com/swagger#/Users) |
| 148 | +>routes. |
| 149 | +
|
| 150 | +Now we're going to use the simple API object to actually request data from the _TheTVDB.com_ REST endpoints. First and |
| 151 | +foremost we have to invoke the _/login_ route once. This will induce the remote API to issue a brand new |
| 152 | +[JSON Web Token](https://en.wikipedia.org/wiki/JSON_Web_Token) which will be needed for further authentication. After we |
| 153 | +have successfully requested a JWT, we can now go on to actually retrieve some data from the API. |
| 154 | +```java |
| 155 | + api.login(); // We could also use "api.init()" which does exactly the same |
| 156 | + |
| 157 | + // Set the preferred language. If possible the remote API will return the requested data in this language |
| 158 | + // If not set, "en"' is the default |
| 159 | + api.setLanguage("it"); |
| 160 | + |
| 161 | + // Alternatively: invoking the "/languages" endpoint will get us a list of all supported languages |
| 162 | + List<Language> allLanguages = api.getAvailableLanguages(); |
| 163 | + Language italian = allLanguages.stream() |
| 164 | + .filter(l -> l.getName().equals("italiano")).findFirst().get(); |
| 165 | + api.setLanguage(italian.getAbbreviation()); |
| 166 | +``` |
| 167 | +>The connector comes with some integrated auto-login functionality, which will automatically try to request a new JWT |
| 168 | +>in case the authorization failed. Although this might come in handy at times, it is **strongly recommended** to manually |
| 169 | +>call "/login" route before requesting any data from the _TheTVDB.com_ API. |
| 170 | +
|
| 171 | +As you can see the JSON content received from the remote API has already been mapped into a `Language` |
| 172 | +[DTO](https://en.wikipedia.org/wiki/Data_transfer_object). These objects are available for all routes returning complex |
| 173 | +values like TV Series information, movies or actors. The actual metadata can be accessed through various getters in the |
| 174 | +usual object-oriented way. |
| 175 | + |
| 176 | +Finally, let's see how to query for specific information. Let's imagine we would like to get all episodes of season 3 |
| 177 | +for a specific TV Series. We can do that by using a corresponding set of `QueryParameters`. |
| 178 | +```java |
| 179 | + long seriesID = 296762; |
| 180 | + QueryParameters query = TheTVDBApiFactory.createQueryParameters(); |
| 181 | + query.addParameter(Query.Series.AIREDSEASON, "3"); |
| 182 | + |
| 183 | + // Use your own custom set of query parameters |
| 184 | + List<Episode> seasonThree = api.queryEpisodes(seriesID, query); |
| 185 | + |
| 186 | + System.out.println("Here come all the episodes of season 3:"); |
| 187 | + seasonThree.stream().forEach(e -> System.out.println( |
| 188 | + e.getAiredSeason() + "." + e.getAiredEpisodeNumber() + ": " + e.getEpisodeName())); |
| 189 | +``` |
| 190 | +``` |
| 191 | +Here come all the episodes of season 3: |
| 192 | +3.1: Parce Domine |
| 193 | +3.2: The Winter Line |
| 194 | +3.3: The Absence of Field |
| 195 | +... |
| 196 | +``` |
| 197 | + |
| 198 | +For certain use cases the connector provides additional shortcut methods. Querying for a specific season is one of them, |
| 199 | +so we could do the exact same example with even less code. |
| 200 | +```java |
| 201 | + long seriesID = 296762; |
| 202 | + |
| 203 | + List<Episode> seasonThree = api.queryEpisodesByAiredSeason(seriesID, 3); |
| 204 | + |
| 205 | + System.out.println("And again, all the episodes of season 3:"); |
| 206 | + seasonThree.stream().forEach(e -> System.out.println( |
| 207 | + e.getAiredSeason() + "." + e.getAiredEpisodeNumber() + ": " + e.getEpisodeName())); |
| 208 | +``` |
| 209 | +``` |
| 210 | +And again, all the episodes of season 3: |
| 211 | +3.1: Parce Domine |
| 212 | +3.2: The Winter Line |
| 213 | +3.3: The Absence of Field |
| 214 | +... |
| 215 | +``` |
| 216 | + |
| 217 | +And that's basically it! Go and check out the documentation of the main API interface `com.github.m0nk3y2k4.thetvdb.api.TheTVDBApi` |
| 218 | +to find more details on the various endpoint and shortcut methods. |
| 219 | + |
| 220 | +#### Advanced |
| 221 | +We could already see that the connector automatically converts the JSON content into a matching DTO. This is the default |
| 222 | +behavior as it should be quite suitable for most cases, the so called default _layout_. However, two additional _layouts_ |
| 223 | +are available to support a wide variety of operational areas: `JSON` and `Extended` |
| 224 | + |
| 225 | +##### JSON layout |
| 226 | +If the prefabbed DTO's do not meet your requirements or if you prefer to take care of the JSON parsing yourself, this |
| 227 | +is the layout to go with. It supports all basic routes (without shortcut methods though) but instead of mapping the metadata |
| 228 | +into a DTO it will simply return the raw JSON as it was received from the remote API. |
| 229 | +```java |
| 230 | + // Create a new API instance the usual way |
| 231 | + TheTVDBApi api = TheTVDBApiFactory.createApi("API_KEY"); |
| 232 | + |
| 233 | + // Create a JSON layout from the existing API by invoking the "json()" method |
| 234 | + TheTVDBApi.JSON jsonApi = api.json(); |
| 235 | + |
| 236 | + long seriesID = 296762; |
| 237 | + QueryParameters query = TheTVDBApiFactory.createQueryParameters(Map.of(Query.Series.AIREDSEASON, "3")); |
| 238 | + |
| 239 | + JsonNode seasonThreeJSON = jsonApi.queryEpisodes(seriesID, query); |
| 240 | + // jsonApi.queryEpisodesByAiredSeason(seriesID, 3); --> This wont work! Shortcut methods are only available in the default layout |
| 241 | +``` |
| 242 | + |
| 243 | +##### Extended layout |
| 244 | +This layout is basically just an extension of the default layout and provides access to additional (though optional) |
| 245 | +information received from the remote API, namely the "errors" and the "links" JSON nodes. Just like the `JSON` layout, |
| 246 | +it supports all basic routes (without shortcut methods). All methods of this layout will return an `APIResponse<T>` |
| 247 | +object which wraps the actual metadata DTO together with the error and pagination information. |
| 248 | +```java |
| 249 | + // Again, create the layout from any existing API |
| 250 | + TheTVDBApi.Extended extendedApi = api.extended(); |
| 251 | + |
| 252 | + // Get the 2nd page of all episodes for this TV Series (max. 100 per page) |
| 253 | + final long page = 2; |
| 254 | + QueryParameters query = TheTVDBApiFactory.createQueryParameters() |
| 255 | + .addParameter(Query.Series.PAGE, String.valueOf(page)); |
| 256 | + |
| 257 | + APIResponse<List<Episode>> response = extendedApi.queryEpisodes(75760, query); |
| 258 | + |
| 259 | + // Get the metadata. This is actually what the default layout does. |
| 260 | + List<Episode> episodesSecondPage = response.getData(); |
| 261 | + |
| 262 | + // Errors and Links will not always be available and therefore will be returned as Optionals |
| 263 | + response.getErrors().map(Errors::getInvalidQueryParams).ifPresent(System.err::println); |
| 264 | + boolean morePages = response.getLinks().map(Links::getLast).map(lastPage -> lastPage > page).orElse(false); |
| 265 | +``` |
| 266 | +>Please note that _Errors_ and _Links_ are not always available but only for certain endpoints. See the _TheTVDB.com_ API |
| 267 | +>documentation for detailed information. |
| 268 | +
|
| 269 | +##### Proxy |
| 270 | +The connector will send all requests directly towards the _TheTVDB.com_ [RESTful API](https://api.thetvdb.com/). In case |
| 271 | +your runtime environment is not able to access this resource directly, you can instruct the connector to send its requests |
| 272 | +to a different host which will forward them to the remote API. |
| 273 | +```java |
| 274 | + Proxy localProxy = TheTVDBApiFactory.createProxy("https", "my.local.proxy", 10000); |
| 275 | + TheTVDBApi proxiedApi = TheTVDBApiFactory.createApi("API_KEY", localProxy); |
| 276 | + |
| 277 | + // Data will be requested from "https://my.local.proxy:10000/movies/2559" |
| 278 | + Movie excellent = proxiedApi.getMovie(2559); |
| 279 | +``` |
| 280 | + |
| 281 | +## Development |
| 282 | +#### Build |
| 283 | +After cloning the repository the connector can be build via Apache Maven: |
| 284 | +```shell script |
| 285 | +mvn clean install |
| 286 | +``` |
| 287 | +The build process will generate the following content, all stored inside the `/target` folder: |
| 288 | +- Artifacts |
| 289 | + - `thetvdb-java-api-{VERSION}.jar` contains the actual connector artifact without dependencies |
| 290 | + - `thetvdb-java-api-{VERSION}-jar-with-dependencies.jar` contains the actual connector artifact will all runtime |
| 291 | + dependencies included |
| 292 | + - `thetvdb-java-api-{VERSION}-javadoc.jar` contains the packed JavaDoc documentation |
| 293 | + - `thetvdb-java-api-{VERSION}-sources.jar` contains the packed source code of the connector |
| 294 | +- Documentation |
| 295 | + - Available through the `-javadoc.jar` artifact or directly at `/apidocs/index.html` |
| 296 | +- Tests |
| 297 | + - jacoco code coverage report available at `/site/jacoco/index.html` |
| 298 | + |
| 299 | +#### Integration Tests |
| 300 | +Integration tests are not part of the default build process as they are executed against the actual _TheTVDB.com_ remote |
| 301 | +API and thus require some additional configuration as well as an active Internet connection. Integration tests can be |
| 302 | +setup and executed with the following steps: |
| 303 | + |
| 304 | +1. Create a new file `/src/integration-tests/resources/thetvdbapi.properties` and set the _TheTVDB.com_ API-Key, user |
| 305 | +key and user name you'd like to be used for the tests. You can use the available `thetvdbapi.properties.sample` file as |
| 306 | +a template. |
| 307 | + |
| 308 | +2. Build the project with the `integration-tests` maven profile: |
| 309 | + ```shell script |
| 310 | + mvn verify -P integration-tests |
| 311 | + ``` |
| 312 | + |
| 313 | +3. _OPTIONAL_: Instead of providing the authentication settings via the `thetvdbapi.properties` file you may also set |
| 314 | +them directly as command line arguments: |
| 315 | + ```shell script |
| 316 | + mvn verify -P integration-tests -Dintegration.thetvdb.com.apikey=APIKEY -Dintegration.thetvdb.com.userkey=USERKEY -Dintegration.thetvdb.com.username=USERNAME |
| 317 | + ``` |
| 318 | + |
| 319 | +## Status |
| 320 | +Project is: _in progress_ |
| 321 | + |
| 322 | +Ongoing development of a connector compliant to the upcoming _TheTVDB.com_ APIv4 interface. |
| 323 | + |
| 324 | +## License |
| 325 | +This project is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) |
| 326 | +>Bear in mind that you might have to negotiate a distinct [license model](https://thetvdb.com/api-information) with |
| 327 | +>_TheTVDB.com, LLC._, e.g. when using their API service as part of a commercial product. |
0 commit comments