diff --git a/Contents/Code/utils/common.py b/Contents/Code/utils/common.py index 38898cd..bea3c48 100644 --- a/Contents/Code/utils/common.py +++ b/Contents/Code/utils/common.py @@ -13,7 +13,7 @@ class CommonUtils: ''' the name of the Agent ''' AGENT_NAME = "MyAnimeList.net" ''' the library languages ''' - AGENT_LANGUAGES = [Locale.Language.English] + AGENT_LANGUAGES = [Locale.Language.English, 'fr', 'zh', 'sv', 'no', 'da', 'fi', 'nl', 'de', 'it', 'es', 'pl', 'hu', 'el', 'tr', 'ru', 'he', 'ja', 'pt', 'cs', 'ko', 'sl', 'hr'] ''' is the agent a primary provider of the metadata ''' AGENT_PRIMARY_PROVIDER = True ''' allows other agents to provide metadata ''' diff --git a/Contents/Code/utils/jikan.py b/Contents/Code/utils/jikan.py index 60948dd..91d8b16 100644 --- a/Contents/Code/utils/jikan.py +++ b/Contents/Code/utils/jikan.py @@ -4,11 +4,11 @@ class JikanApiUtils: - API_MAIN = "https://api.jikan.moe/v3" + API_MAIN = "https://api.jikan.moe/v4" API_DETAILS = "/anime/{id}" - API_SEARCH = "/search/anime?q={title}" - API_EPISODES = API_DETAILS + "/episodes/{page}" - API_STAFF = API_DETAILS + "/characters_staff" + API_SEARCH = "/anime?q={title}" + API_EPISODES = API_DETAILS + "/episodes?page={page}" + API_STAFF = API_DETAILS + "/characters" API_PICTURES = API_DETAILS + "/pictures" API_PERSON = "/person/{id}/pictures" API_CHARACTER = "/character/{id}/pictures" @@ -59,14 +59,14 @@ def search(self, title, results, lang): results.Append(MetadataSearchResult(id=apiMal_id, name=apiTitle, year=apiAired, score=matchScore, lang=lang)) else: Log.Debug("[" + self.AGENT_NAME + "] " + "Parsing search results") - resultsArray = searchResult["results"] + resultsArray = searchResult["data"] Log.Info("[" + self.AGENT_NAME + "] " + str(len(resultsArray)) + " Results found") for show in resultsArray: apiMal_id = str(self.COMMON_UTILS.getJsonValue("mal_id", show)) apiTitle = str(self.COMMON_UTILS.getJsonValue("title", show)) - apiAired = str(self.COMMON_UTILS.getYear("start_date", show)) + apiAired = str(self.COMMON_UTILS.getYear("from", show["aired"])) matchScore = self.COMMON_UTILS.calcMatchScore(title, apiTitle) Log.Debug("[" + self.AGENT_NAME + "] " + "ID=" + str(apiMal_id) + " Title='" + str(apiTitle) + "' Year=" + str(apiAired) + " MatchScore=" + str(matchScore)) @@ -83,175 +83,187 @@ def getDetails(self, metadata): detailsUrl = self.API_MAIN + self.API_DETAILS.format(id=metadata.id) detailResponse = self.COMMON_UTILS.getResponse(detailsUrl) - + if detailResponse is not None: detailResult = JSON.ObjectFromString(detailResponse) - - # get the MyAnimeList ID from the JSON response and add it to the metadata - apiId = self.COMMON_UTILS.getJsonValue("mal_id", detailResult) - if apiId is not None: - Log.Debug("[" + self.AGENT_NAME + "] " + "ID: " + str(apiId)) - metadata.id = str(apiId) - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "ID was not available ") - - # get the Title that the user desires from the JSON response and add it to the metadata, if that title isn't available then default to the main - preferredTitle = str(Prefs["preferredTitle"]) - titleLanguage = None - - if preferredTitle == "Japanese": - titleLanguage = "title_japanese" - elif preferredTitle == "English": - titleLanguage = "title_english" - else: - titleLanguage = "title" - - apiTitle = self.COMMON_UTILS.getJsonValue(titleLanguage, detailResult) - if apiTitle is not None: - Log.Debug("[" + self.AGENT_NAME + "] " + "Title (" + preferredTitle + "): " + str(apiTitle)) - metadata.title = str(apiTitle) - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "title for language (" + titleLanguage + ") could not be retrieved, falling back to main title") - - apiTitle = self.COMMON_UTILS.getJsonValue("title", detailResult) - metadata.title = str(apiTitle) - Log.Debug("[" + self.AGENT_NAME + "] " + "Title: " + str(apiTitle)) - - # get the summary from the JSON response and add it to the metadata - apiSummary = self.COMMON_UTILS.getJsonValue("synopsis", detailResult) - if apiSummary is not None: - Log.Debug("[" + self.AGENT_NAME + "] " + "Summary: " + str(apiSummary)) - metadata.summary = str(apiSummary) - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Summary was not available ") - - # get the rating from the JSON response and add it to the metadata - apiRating = self.COMMON_UTILS.getJsonValue("score", detailResult) - if apiRating is not None: - Log.Debug("[" + self.AGENT_NAME + "] " + "Rating: " + str(apiRating)) - metadata.rating = float(apiRating) - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Rating was not available ") - - # get the year when it originally aired from the JSON response and add it to the metadata - apiYear = self.COMMON_UTILS.getDate("from", detailResult["aired"]) - if apiYear is not None: - Log.Debug("[" + self.AGENT_NAME + "] " + "Year: " + str(apiYear)) - metadata.originally_available_at = apiYear - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Year was not available ") - - # get the content rating from the JSON response and add it to the metadata - apiContentRating = self.COMMON_UTILS.getJsonValue("rating", detailResult) - if apiContentRating is not None: - Log.Debug("[" + self.AGENT_NAME + "] " + "Content Rating: " + str(apiContentRating)) - metadata.content_rating = str(apiContentRating) - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Content Rating was not available ") - - # get the main poster from the JSON response and add it to the metadata - apiMainPoster = self.COMMON_UTILS.getJsonValue("image_url", detailResult) - if apiMainPoster is not None: - Log.Debug("[" + self.AGENT_NAME + "] " + "Main Poster: " + str(apiMainPoster)) - if metadata.posters[str(apiMainPoster)] is None: - imageContent = self.COMMON_UTILS.getResponse(str(apiMainPoster)) - - metadata.posters[str(apiMainPoster)] = Proxy.Media(imageContent) + data = detailResult['data'] + + if data is not None: + # get the MyAnimeList ID from the JSON response and add it to the metadata + apiId = self.COMMON_UTILS.getJsonValue("mal_id", data) + if apiId is not None: + Log.Debug("[" + self.AGENT_NAME + "] " + "ID: " + str(apiId)) + metadata.id = str(apiId) else: - Log.Debug("[" + self.AGENT_NAME + "] " + "Image is already present (" + str(apiMainPoster) + ")") - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Main Poster was not available ") - - # get the duration from the JSON response, parse it, get milliseconds and add it to the metadata - apiDuration = self.COMMON_UTILS.getJsonValue("duration", detailResult) - if apiDuration is not None: - duration = int(self.COMMON_UTILS.getRegExMatch("^(\d*)", str(apiDuration), 1)) * 60000 - Log.Debug("[" + self.AGENT_NAME + "] " + "Duration: " + str(duration)) - metadata.duration = int(duration) - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Duration was not available ") - - # get the genres from the JSON response and add it to the metadata - apiGenres = self.COMMON_UTILS.getJsonValue("genres", detailResult) - if apiGenres is not None: - genresArray = self.COMMON_UTILS.getArrayFromJsonValue("name", apiGenres) - Log.Debug("[" + self.AGENT_NAME + "] " + "Genres: " + str(genresArray)) - for genre in genresArray: - metadata.genres.add(str(genre)) - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Genres were not available ") - - # get the producers from the JSON response and add it to the metadata - # Note: producers are only set on an individual episodes or a Movie, not on a show or season - #apiProducers= self.COMMON_UTILS.getJsonValue("producers", detailResult) - #if apiProducers is not None: - # producersArray = self.COMMON_UTILS.getArrayFromJsonValue("name", apiProducers) - # Log.Debug("[" + self.AGENT_NAME + "] " + "Producers: " + str(producersArray)) - #else: - # Log.Warn("[" + self.AGENT_NAME + "] " + "Producers were not available ") - - # get the studios from the JSON response and add it to the details dictionary - apiStudios = self.COMMON_UTILS.getJsonValue("studios", detailResult) - if apiStudios is not None: - studiosArray = self.COMMON_UTILS.getArrayFromJsonValue("name", apiStudios) - Log.Debug("[" + self.AGENT_NAME + "] " + "Studios: " + str(studiosArray)) - - metadata.studio = ', '.join(studiosArray) + Log.Warn("[" + self.AGENT_NAME + "] " + "ID was not available ") + + # get the Title that the user desires from the JSON response and add it to the metadata, if that title isn't available then default to the main + preferredTitle = str(Prefs["preferredTitle"]) + titleLanguage = None + + if preferredTitle == "Japanese": + titleLanguage = "title_japanese" + elif preferredTitle == "English": + titleLanguage = "title_english" + else: + titleLanguage = "title" + + apiTitle = self.COMMON_UTILS.getJsonValue(titleLanguage, data) + if apiTitle is not None: + Log.Debug("[" + self.AGENT_NAME + "] " + "Title (" + preferredTitle + "): " + str(apiTitle)) + metadata.title = str(apiTitle) + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "title for language (" + titleLanguage + ") could not be retrieved, falling back to main title") + + apiTitle = self.COMMON_UTILS.getJsonValue("title", data) + metadata.title = str(apiTitle) + Log.Debug("[" + self.AGENT_NAME + "] " + "Title: " + str(apiTitle)) + + # get the summary from the JSON response and add it to the metadata + apiSummary = self.COMMON_UTILS.getJsonValue("synopsis", data) + if apiSummary is not None: + Log.Debug("[" + self.AGENT_NAME + "] " + "Summary: " + str(apiSummary)) + metadata.summary = str(apiSummary) + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Summary was not available ") + + # get the rating from the JSON response and add it to the metadata + apiRating = self.COMMON_UTILS.getJsonValue("score", data) + if apiRating is not None: + Log.Debug("[" + self.AGENT_NAME + "] " + "Rating: " + str(apiRating)) + metadata.rating = float(apiRating) + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Rating was not available ") + + # get the year when it originally aired from the JSON response and add it to the metadata + apiYear = self.COMMON_UTILS.getDate("from", data["aired"]) + if apiYear is not None: + Log.Debug("[" + self.AGENT_NAME + "] " + "Year: " + str(apiYear)) + metadata.originally_available_at = apiYear + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Year was not available ") + + # get the content rating from the JSON response and add it to the metadata + apiContentRating = self.COMMON_UTILS.getJsonValue("rating", data) + if apiContentRating is not None: + Log.Debug("[" + self.AGENT_NAME + "] " + "Content Rating: " + str(apiContentRating)) + metadata.content_rating = str(apiContentRating) + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Content Rating was not available ") + + # get the main poster from the JSON response and add it to the metadata + images = self.COMMON_UTILS.getJsonValue("images", data) + apiMainPoster = self.COMMON_UTILS.getJsonValue("image_url", images["jpg"]) + if apiMainPoster is not None: + Log.Debug("[" + self.AGENT_NAME + "] " + "Main Poster: " + str(apiMainPoster)) + if metadata.posters[str(apiMainPoster)] is None: + imageContent = self.COMMON_UTILS.getResponse(str(apiMainPoster)) + + metadata.posters[str(apiMainPoster)] = Proxy.Media(imageContent) + else: + Log.Debug("[" + self.AGENT_NAME + "] " + "Image is already present (" + str(apiMainPoster) + ")") + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Main Poster was not available ") + + # get the duration from the JSON response, parse it, get milliseconds and add it to the metadata + apiDuration = self.COMMON_UTILS.getJsonValue("duration", data) + if apiDuration is not None: + duration = int(self.COMMON_UTILS.getRegExMatch("^(\d*)", str(apiDuration), 1)) * 60000 + Log.Debug("[" + self.AGENT_NAME + "] " + "Duration: " + str(duration)) + metadata.duration = int(duration) + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Duration was not available ") + + # get the genres from the JSON response and add it to the metadata + apiGenres = self.COMMON_UTILS.getJsonValue("genres", data) + if apiGenres is not None: + genresArray = self.COMMON_UTILS.getArrayFromJsonValue("name", apiGenres) + Log.Debug("[" + self.AGENT_NAME + "] " + "Genres: " + str(genresArray)) + for genre in genresArray: + metadata.genres.add(str(genre)) + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Genres were not available ") + + # get the producers from the JSON response and add it to the metadata + # Note: producers are only set on an individual episodes or a Movie, not on a show or season + #apiProducers= self.COMMON_UTILS.getJsonValue("producers", data) + #if apiProducers is not None: + # producersArray = self.COMMON_UTILS.getArrayFromJsonValue("name", apiProducers) + # Log.Debug("[" + self.AGENT_NAME + "] " + "Producers: " + str(producersArray)) + #else: + # Log.Warn("[" + self.AGENT_NAME + "] " + "Producers were not available ") + + # get the studios from the JSON response and add it to the details dictionary + apiStudios = self.COMMON_UTILS.getJsonValue("studios", data) + if apiStudios is not None: + studiosArray = self.COMMON_UTILS.getArrayFromJsonValue("name", apiStudios) + Log.Debug("[" + self.AGENT_NAME + "] " + "Studios: " + str(studiosArray)) + + metadata.studio = ', '.join(studiosArray) + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Studios were not available ") + + else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Studios were not available ") + Log.Warn("[" + self.AGENT_NAME + "] " + "Jikan API returned no data") + else: Log.Warn("[" + self.AGENT_NAME + "] " + "There was an error requesting a response from the Jikan API") - return None + + return ''' get the episodes for a specific MyAnimeList ID ''' def getEpisodes(self, metadata): Log.Info("[" + self.AGENT_NAME + "] " + "Requesting Episodes from Jikan") - - firstPage = 1 - - episodesUrl = self.API_MAIN + self.API_EPISODES.format(id=metadata.id,page=firstPage) - episodeResponse = self.COMMON_UTILS.getResponse(episodesUrl) - - if episodeResponse is not None: - episodesResult = JSON.ObjectFromString(episodeResponse) - maxPages = self.COMMON_UTILS.getJsonValue("episodes_last_page", episodesResult) - - # parse the first page and add them to the metadata - self.parseEpisodePage(metadata, firstPage, maxPages, episodesResult) - - # if there are more pages, parse them too and add them to the metadata - for currentPage in range(firstPage + 1, maxPages + 1): - - ## Wait 0.5 seconds to not go beyond the rate limit of the Jikan API - time.sleep(0.5) - - nextPageUrl = self.API_MAIN + self.API_EPISODES.format(id=metadata.id,page=currentPage) - nextPageResult = JSON.ObjectFromString(self.COMMON_UTILS.getResponse(nextPageUrl)) - - if nextPageResult is not None: - self.parseEpisodePage(metadata, currentPage, maxPages, nextPageResult) - - else: - Log.Warn("[" + self.AGENT_NAME + "] " + "Episodes were not available or there was an error retrieving them") - + + page = 1 + nextPage = True + + # iterate each page if there is a next page + while nextPage == True: + ## reset nextPage to prevent an endless loop + nextPage = False + ## Wait 0.5 seconds to not go beyond the rate limit of the Jikan API + time.sleep(0.5) + + episodesUrl = self.API_MAIN + self.API_EPISODES.format(id=metadata.id,page=page) + episodesResponse = self.COMMON_UTILS.getResponse(episodesUrl) + if episodesResponse is not None: + episodesResult = JSON.ObjectFromString(episodesResponse) + pagination = episodesResult["pagination"] + data = episodesResult["data"] + + if data is not None: + nextPage = pagination["has_next_page"] + + # parse episode page + self.parseEpisodePage(metadata, data, page) + + page = page + 1 + + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Jikan API returned no data") + break + + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Episodes were not available or there was an error retrieving them") + break return - + ''' parse the specific page of episodes and add the information to the metadata ''' - def parseEpisodePage(self, metadata, current, max, page): - Log.Info("[" + self.AGENT_NAME + "] " + "Parsing Episodes page " + str(current) + "/" + str(max)) - - episodes = self.COMMON_UTILS.getJsonValue("episodes", page) - + def parseEpisodePage(self, metadata, episodes, page): + Log.Info("[" + self.AGENT_NAME + "] " + "Parsing Episodes page " + str(page)) + for episode in episodes: # get the episode number and title of the episode # both the number and title are required on MyAnimeList and define that an episode even exist. - number = self.COMMON_UTILS.getJsonValue("episode_id", episode) + number = self.COMMON_UTILS.getJsonValue("mal_id", episode) title = self.COMMON_UTILS.getJsonValue("title", episode) - + # get the aired date of the episode # unlike the number and title, the aired date can be unavailable (null on the jikan API) # plex needs a valid date so that the episode can be considered for "next episode" @@ -259,15 +271,15 @@ def parseEpisodePage(self, metadata, current, max, page): aired = self.COMMON_UTILS.getDate("aired", episode) except: aired = self.COMMON_UTILS.getNowDate() - + Log.Debug("[" + self.AGENT_NAME + "] Episode " + str(number) + ": " + str(title) + " - " + str(aired)) - + plexEpisode = metadata.seasons[1].episodes[int(number)] plexEpisode.title = str(title) plexEpisode.originally_available_at = aired - + return - + ''' get the pictures of the anime Note: Pictures on MyAnimeList can contain Pictures that could be either a Poster or a Background image @@ -280,23 +292,28 @@ def getPictures(self, metadata): picturesUrl = self.API_MAIN + self.API_PICTURES.format(id=metadata.id) pictureResponse = self.COMMON_UTILS.getResponse(picturesUrl) - + if pictureResponse is not None: picturesResult = JSON.ObjectFromString(pictureResponse) - - picArr = self.COMMON_UTILS.getJsonValue("pictures", picturesResult) - pictures = self.COMMON_UTILS.getArrayFromJsonValue("large", picArr) - - for picture in pictures: - Log.Debug("[" + self.AGENT_NAME + "] " + "Poster: " + str(picture)) - - if metadata.posters[str(picture)] is None: - imageContent = self.COMMON_UTILS.getResponse(str(picture)) - - metadata.posters[str(picture)] = Proxy.Media(imageContent) - else: - Log.Debug("[" + self.AGENT_NAME + "] " + "Image is already present (" + str(picture) + ")") - + data = picturesResult["data"] + + if data is not None: + for picture in data: + image = self.COMMON_UTILS.getJsonValue("image_url", picture["jpg"]) + + Log.Debug("[" + self.AGENT_NAME + "] " + "Poster: " + str(image)) + + if metadata.posters[str(image)] is None: + imageContent = self.COMMON_UTILS.getResponse(str(image)) + metadata.posters[str(image)] = Proxy.Media(imageContent) + else: + Log.Debug("[" + self.AGENT_NAME + "] " + "Image is already present (" + str(image) + ")") + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Jikan API returned no data") + + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Pictures were not available or there was an error retrieving them") + return ''' @@ -313,57 +330,65 @@ def getCharacters(self, metadata): ## Wait 0.5 seconds to not go beyond the rate limit of the Jikan API time.sleep(0.5) - - staffUrl = self.API_MAIN + self.API_STAFF.format(id=metadata.id) - staffResponse = self.COMMON_UTILS.getResponse(staffUrl) - - metadata.roles.clear() - - if staffResponse is not None: - staffResult = JSON.ObjectFromString(staffResponse) - - charactersArr = self.COMMON_UTILS.getJsonValue("characters", staffResult) - - for character in charactersArr: - #Log.Debug("[" + self.AGENT_NAME + "] " + "Character: " + str(character)) - - charId = self.COMMON_UTILS.getJsonValue("mal_id", character) - charName = self.COMMON_UTILS.getJsonValue("name", character) - charImage = self.COMMON_UTILS.getJsonValue("image_url", character) - vaId = None - vaName = None - vaLanguage = None - vaImage = None - - voiceActors = self.COMMON_UTILS.getJsonValue("voice_actors", character) - - for voiceActor in voiceActors: - vaLang = self.COMMON_UTILS.getJsonValue("language", voiceActor) - - if vaLang == preferredVaLanguage: - vaId = self.COMMON_UTILS.getJsonValue("mal_id", voiceActor) - vaName = self.COMMON_UTILS.getJsonValue("name", voiceActor) - if preferredCharacterImage == "Voice Actor": - image_url = self.COMMON_UTILS.getJsonValue("image_url", voiceActor) - vaImage = image_url.replace("r/42x62/", "") - vaLanguage = vaLang - break - - Log.Debug("[" + self.AGENT_NAME + "] " - + "Character: #" + str(charId) + " - " - + str(charName) + " - " - + str(charImage) + " - " - + str(vaId) + " - " - + str(vaName) + " - " - + str(vaLanguage) + " - " - + str(vaImage)) - - newRole = metadata.roles.new() - newRole.name = vaName - newRole.role = charName - if preferredCharacterImage == "Voice Actor": - newRole.photo = vaImage - else: - newRole.photo = charImage - + + charactersUrl = self.API_MAIN + self.API_STAFF.format(id=metadata.id) + charactersResponse = self.COMMON_UTILS.getResponse(charactersUrl) + + if charactersResponse is not None: + charactersResult = JSON.ObjectFromString(charactersResponse) + data = charactersResult["data"] + + if data is not None: + metadata.roles.clear() + + for item in data: + char = self.COMMON_UTILS.getJsonValue("character", item) + charId = self.COMMON_UTILS.getJsonValue("mal_id", char) + charName = self.COMMON_UTILS.getJsonValue("name", char) + images = self.COMMON_UTILS.getJsonValue("images", char) + charImage = self.COMMON_UTILS.getJsonValue("image_url", images["jpg"]) + + voiceActors = self.COMMON_UTILS.getJsonValue("voice_actors", item) + vaId = None + vaName = None + vaLanguage = None + vaImage = None + + # iterate over all voice actors for that character + for voiceActor in voiceActors: + vaLang = self.COMMON_UTILS.getJsonValue("language", voiceActor) + + if vaLang == preferredVaLanguage: + person = self.COMMON_UTILS.getJsonValue("person", voiceActor) + vaId = self.COMMON_UTILS.getJsonValue("mal_id", person) + vaName = self.COMMON_UTILS.getJsonValue("name", person) + if preferredCharacterImage == "Voice Actor": + images = self.COMMON_UTILS.getJsonValue("images", person) + vaImage = self.COMMON_UTILS.getJsonValue("image_url", images["jpg"]) + vaLanguage = vaLang + break + + Log.Debug("[" + self.AGENT_NAME + "] " + + "Character: #" + str(charId) + " - " + + str(charName) + " - " + + str(charImage) + " - " + + str(vaId) + " - " + + str(vaName) + " - " + + str(vaLanguage) + " - " + + str(vaImage) + ) + + # add a new role to the metadata + newRole = metadata.roles.new() + newRole.name = vaName + newRole.role = charName + if preferredCharacterImage == "Voice Actor": + newRole.photo = vaImage + else: + newRole.photo = charImage + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Jikan API returned no data") + else: + Log.Warn("[" + self.AGENT_NAME + "] " + "Pictures were not available or there was an error retrieving them") + return \ No newline at end of file diff --git a/VERSION b/VERSION index 32dbe52..6bfa55e 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ -#Sat, 08 Jan 2022 09:11:23 +0100 +#Mon, 11 Apr 2022 19:19:26 +0200 major.number=7 -minor.number=0 -build.number=3 +minor.number=1 +build.number=0