diff --git a/features/ingest.feature b/features/ingest.feature index d0211f4761..c25ce8fa5d 100644 --- a/features/ingest.feature +++ b/features/ingest.feature @@ -477,18 +477,29 @@ Feature: Fetch From Ingest "type":"picture", "state":"ingested", "renditions":{ - "baseImage":{ - "width":1400 - }, - "thumbnail":{ - - }, - "original":{ - + "original": { + "poi": { + "y": 1193, + "x": 2128 + }, + "href": "http://content.reuters.com/auth-server/content/tag_reuters.com_2014_newsml_LYNXMPEA6F0MT_2/tag_reuters.com_2014_binary_LYNXMPEA6F0MT-BASEIMAGE?auth_token=fake_token", + "mimetype": "image/jpeg", + "media": "599e31ec1d41c833e0b8a830", + "width": 3489, + "height": 2296 }, - "viewImage":{ + "baseImage": { + "poi": { + "y": 478, + "x": 854 + }, + "href": "http://content.reuters.com/auth-server/content/tag_reuters.com_2014_newsml_LYNXMPEA6F0MT_2/tag_reuters.com_2014_binary_LYNXMPEA6F0MT-BASEIMAGE?auth_token=fake_token", + "mimetype": "image/jpeg", + "media": "599e31ed1d41c833e0b8a840", + "width": 1400, + "height": 921 } - } + } }, { "type":"text", @@ -497,11 +508,28 @@ Feature: Fetch From Ingest "featuremedia":{ "state": "ingested", "renditions":{ - "baseImage":{ - "width":1400 - }, - "original":{ - } + "original": { + "poi": { + "y": 1193, + "x": 2128 + }, + "href": "http://content.reuters.com/auth-server/content/tag_reuters.com_2014_newsml_LYNXMPEA6F0MT_2/tag_reuters.com_2014_binary_LYNXMPEA6F0MT-BASEIMAGE?auth_token=fake_token", + "mimetype": "image/jpeg", + "media": "599e31ec1d41c833e0b8a830", + "width": 3489, + "height": 2296 + }, + "baseImage": { + "poi": { + "y": 478, + "x": 854 + }, + "href": "http://content.reuters.com/auth-server/content/tag_reuters.com_2014_newsml_LYNXMPEA6F0MT_2/tag_reuters.com_2014_binary_LYNXMPEA6F0MT-BASEIMAGE?auth_token=fake_token", + "mimetype": "image/jpeg", + "media": "599e31ed1d41c833e0b8a840", + "width": 1400, + "height": 921 + } } } } @@ -514,7 +542,7 @@ Feature: Fetch From Ingest @provider Scenario: Ingest ninjs with embedded items Given empty "ingest" - When we fetch from "ninjs" ingest "ninjs4.json" (mocking with "ninjs4_mock.json") + When we fetch from "ninjs" ingest "ninjs4.json" And we get "/ingest" Then we get existing resource """ @@ -524,19 +552,22 @@ Feature: Fetch From Ingest "type":"picture", "state":"ingested", "headline": "Polizeihunde sollen effizienter trainiert werden – Klone sollen die Lösung sein.", - "renditions":{ - "baseImage":{ - "width":1400 + "renditions": { + "original": { + "media": "Polizeihund-China-2.jpg", + "href": "https://img.futurezone.de/img/science/origs216742511/239706555-w1280-h960-q85/Polizeihund-China-2.jpg", + "mimetype": "image\/jpeg", + "height": 853, + "width": 1280 }, - "thumbnail":{ - - }, - "original":{ - - }, - "viewImage":{ + "baseImage": { + "media": "Polizeihund-China-2.jpg", + "href": "https://img.futurezone.de/img/science/origs216742511/239706555-w1280-h960-q85/Polizeihund-China-2.jpg", + "mimetype": "image\/jpeg", + "height": 853, + "width": 1280 } - } + } }, { "type":"picture", @@ -549,13 +580,22 @@ Feature: Fetch From Ingest "associations":{ "featuremedia":{ "state": "ingested", - "renditions":{ - "baseImage":{ - "width":1400 - }, - "original":{ - } - } + "renditions": { + "original": { + "media": "Polizeihund-China-2.jpg", + "href": "https://img.futurezone.de/img/science/origs216742511/239706555-w1280-h960-q85/Polizeihund-China-2.jpg", + "mimetype": "image\/jpeg", + "height": 853, + "width": 1280 + }, + "baseImage": { + "media": "Polizeihund-China-2.jpg", + "href": "https://img.futurezone.de/img/science/origs216742511/239706555-w1280-h960-q85/Polizeihund-China-2.jpg", + "mimetype": "image\/jpeg", + "height": 853, + "width": 1280 + } + } } } } @@ -591,25 +631,27 @@ Feature: Fetch From Ingest "headline":"German Air Force Museum", "state":"ingested", "renditions":{ - "baseImage" : { - "width" : 1400, - "height" : 1074, - "mimetype" : "image/jpeg" - }, - "thumbnail" : { - "width":156, - "height":120, - "mimetype" : "image/jpeg" - }, - "original" : { - "width" : 800, - "height" : 614, - "mimetype" : "image/jpeg" + "baseImage": { + "poi": { + "y": 382, + "x": 784 + }, + "media": "599faa351d41c8fdc696d904", + "width": 1400, + "height": 934, + "mimetype": "image/jpeg", + "href": "http://localhost:5000/api/upload-raw/599faa351d41c8fdc696d904?_schema=http" }, - "viewImage":{ - "width" : 640, - "height" : 491, - "mimetype" : "image/jpeg" + "original": { + "poi": { + "y": 1646, + "x": 3368 + }, + "media": "599faa331d41c8fdc696d8b4", + "width": 6016, + "height": 4016, + "mimetype": "image/jpeg", + "href": "http://content.reuters.com/auth-server/content/tag_reuters.com_2014_newsml_LYNXMPEA6F0MT_2/tag_reuters.com_2014_binary_LYNXMPEA6F0MT-BASEIMAGE?auth_token=fake_token" } } } diff --git a/superdesk/default_settings.py b/superdesk/default_settings.py index d7b7fcd239..c6994b9cf3 100644 --- a/superdesk/default_settings.py +++ b/superdesk/default_settings.py @@ -581,6 +581,7 @@ def local_to_utc_hour(hour): }, } +NINJS_COMMON_RENDITIONS = list(RENDITIONS["picture"].keys()) #: BCRYPT work factor BCRYPT_GENSALT_WORK_FACTOR = 12 diff --git a/superdesk/io/feed_parsers/ninjs.py b/superdesk/io/feed_parsers/ninjs.py index 58511cf25f..80a8295375 100644 --- a/superdesk/io/feed_parsers/ninjs.py +++ b/superdesk/io/feed_parsers/ninjs.py @@ -120,8 +120,8 @@ def _transform_from_ninjs(self, ninjs): associated_item["versioncreated"] = self.datetime(associated_item["versioncreated"]) item["associations"][key] = deepcopy(associated_item) - if ninjs.get("renditions", {}).get("baseImage"): - item["renditions"] = {"baseImage": {"href": ninjs.get("renditions", {}).get("original", {}).get("href")}} + if ninjs.get("renditions"): + item["renditions"] = self.parse_renditions(ninjs["renditions"]) if ninjs.get("located"): item["dateline"] = {"located": {"city": ninjs.get("located")}} @@ -146,6 +146,42 @@ def _transform_from_ninjs(self, ninjs): return item + def parse_renditions(self, renditions): + rend = {} + for rendition_name, rendition_data in renditions.items(): + parsed_rendition = {} + + # Parse href + href = rendition_data.get("href", "") + if isinstance(href, str) and href: + parsed_rendition["href"] = href + + # Parse width and height + width = rendition_data.get("width", None) + height = rendition_data.get("height", None) + if isinstance(width, int) and isinstance(height, int): + parsed_rendition["width"] = width + parsed_rendition["height"] = height + + # Parse mimetype + mimetype = rendition_data.get("mimetype", "") + if isinstance(mimetype, str) and mimetype: + parsed_rendition["mimetype"] = mimetype + + # Parse poi + poi = rendition_data.get("poi", {}) + if isinstance(poi, dict) and "x" in poi and "y" in poi: + parsed_rendition["poi"] = {"x": poi["x"], "y": poi["y"]} + + # Parse media + media = rendition_data.get("media", "") + if isinstance(media, str) and media: + parsed_rendition["media"] = media + + if parsed_rendition: + rend[rendition_name] = parsed_rendition + return rend + def _format_qcodes(self, items): subjects = [] for item in items: diff --git a/superdesk/publish/formatters/ninjs_formatter.py b/superdesk/publish/formatters/ninjs_formatter.py index 78c8a1449a..010dcc904b 100644 --- a/superdesk/publish/formatters/ninjs_formatter.py +++ b/superdesk/publish/formatters/ninjs_formatter.py @@ -142,7 +142,7 @@ def __init__(self): self.format_type = "ninjs" self.can_preview = True self.can_export = True - self.internal_renditions = ["original"] + self.internal_renditions = app.config.get("NINJS_COMMON_RENDITIONS", []) + ["original"] def format(self, article, subscriber, codes=None): try: diff --git a/tests/publish/formatters/ninjs_formatter_test.py b/tests/publish/formatters/ninjs_formatter_test.py index b6ecea8c33..586a05272b 100644 --- a/tests/publish/formatters/ninjs_formatter_test.py +++ b/tests/publish/formatters/ninjs_formatter_test.py @@ -187,6 +187,12 @@ def test_picture_formatter(self): "href": "https://one-api.aap.com.au/api/v3/Assets/20150723001158606583/Original/download", "mimetype": "image/jpeg", }, + "viewImage": { + "height": 401, + "href": "http://localhost:5000/api/upload/55b032041d41c8d278d21b6f/raw?_schema=http", + "mimetype": "image/jpeg", + "width": 640, + }, }, "headline": "AMAZING PICTURE", "pubstatus": "usable", @@ -203,7 +209,7 @@ def test_picture_formatter(self): "embargoed": embargoed.isoformat(), } self.assertEqual(expected, json.loads(doc)) - self.assertNotIn("viewImage", json.loads(doc).get("renditions")) + self.assertIn("viewImage", json.loads(doc).get("renditions")) def test_composite_formatter(self): article = {