Skip to content

Commit d1e40a5

Browse files
committed
fix(verify): reject maker marketing shots in the Commons photo backfill
The backfill accepted a Galaxy Tab S11 Ultra photo that an uploader had copied from Samsung's website and tagged CC0. Reject a file whose Commons Credit names a website, press, newsroom or official source, or whose Artist is the device maker. VERSION 8 re-inspects every cached decision under the rule, so the v6 upgrade path goes. Refs #98
1 parent 80b8324 commit d1e40a5

2 files changed

Lines changed: 20 additions & 23 deletions

File tree

‎app/verify/wikipedia_image_backfill.py‎

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@
2626
variant_conflict,
2727
)
2828

29-
VERSION = 7
29+
VERSION = 8
3030
CATEGORIES = ("smartphone", "laptop", "monitor", "tablet", "watch", "pda")
3131
BAD_IMAGE = re.compile(
3232
r"(?<![A-Za-z0-9])(?:logo|logotype|wordmark|icon|emblem|flag|symbol|diagram|chart|screenshot|placeholder|render|advertisement|battery|headquarters?|building|campus|series|lineup|packaging|시리즈)(?![A-Za-z0-9])",
3333
re.I,
3434
)
3535
GROUP_IMAGE = re.compile(r"_and_.*(?:Xiaomi|Samsung|Huawei|OnePlus|Oppo|Vivo)", re.I)
3636
NON_PHONE_MODEL = re.compile(r"^(?:Surface \d+|Palm TX)$", re.I)
37+
# A maker's own marketing shot re-tagged free by a third-party uploader is not a free file.
38+
CORPORATE_SOURCE = re.compile(r"\b(?:web ?site|press|newsroom|media kit|official)\b", re.I)
3739
BAD_LICENSE = re.compile(r"non.free|fair.use|all.rights.reserved|unknown|unclear|copyrighted", re.I)
3840
FREE_LICENSE = re.compile(
3941
r"^(?:CC[- ]?BY(?:[- ]?SA)?[- ]?[1-4](?:\.0)?|CC0(?:[- ]?1\.0)?|PUBLIC DOMAIN)$", re.I
@@ -178,7 +180,7 @@ def load_decisions(path: Path) -> dict[str, dict[str, Any]]:
178180
item = json.loads(line)
179181
except ValueError:
180182
continue
181-
if item.get("version") in {6, VERSION} and isinstance(item.get("path"), str):
183+
if item.get("version") == VERSION and isinstance(item.get("path"), str):
182184
decisions[item["path"]] = item
183185
return decisions
184186

@@ -271,6 +273,11 @@ def inspect(url: str, fetcher: CommonsFetcher, name: str = "") -> dict[str, str]
271273
attribution = metadata_value(metadata, "Artist") or metadata_value(metadata, "Credit")
272274
if not attribution:
273275
return {"reason": "bad_license", "file": filename, "raw_license": license_id}
276+
maker = name.split()[0].lower() if name.split() else ""
277+
if CORPORATE_SOURCE.search(metadata_value(metadata, "Credit")) or (
278+
maker and attribution.strip().lower() == maker
279+
):
280+
return {"reason": "bad_license", "file": filename, "raw_license": license_id}
274281
return {
275282
"reason": "accepted",
276283
"file": filename,
@@ -346,27 +353,6 @@ def run(
346353
results.append(decision)
347354
print(f"Skipping {rel}: {decision['error']}", flush=True)
348355
continue
349-
if (
350-
decision is not None
351-
and decision.get("version") == 6
352-
and decision.get("article") == article
353-
):
354-
decision = dict(decision, version=VERSION)
355-
if decision.get("reason") == "accepted" and (
356-
BAD_IMAGE.search(str(decision.get("file") or ""))
357-
or GROUP_IMAGE.search(str(decision.get("file") or ""))
358-
or NON_PHONE_MODEL.search(str(record.get("name") or ""))
359-
or not filename_matches_model(
360-
str(record.get("name") or ""), str(decision.get("file") or "")
361-
)
362-
or variant_conflict(
363-
str(record.get("name") or ""), str(decision.get("file") or "").replace("_", " ")
364-
)
365-
):
366-
decision["reason"] = "logo_like"
367-
for key in ("image_url", "image_license", "image_attribution"):
368-
decision.pop(key, None)
369-
append_cache(decision, cache_path)
370356
if (
371357
decision is None
372358
or decision.get("article") != article

‎tests/verify/test_wikipedia_image_backfill.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ def test_accepts_only_free_photo_with_attribution() -> None:
8080
assert fetcher.calls == 2
8181

8282

83+
@pytest.mark.parametrize("artist,credit", [
84+
("A photographer", "Example Website"),
85+
("Example", "Own work"),
86+
])
87+
def test_rejects_maker_marketing_shot_tagged_free(artist: str, credit: str) -> None:
88+
metadata = {**meta("CC0", artist=artist), "Credit": {"value": credit}}
89+
fetcher = FakeFetcher("Example_phone.jpg", metadata)
90+
result = inspect("https://en.wikipedia.org/wiki/Example_phone", fetcher, "Example Phone")
91+
assert result["reason"] == "bad_license"
92+
93+
8394
def test_rejects_render_and_nonfree() -> None:
8495
render = FakeFetcher("Example_phone.png", meta("CC-BY-SA-4.0"))
8596
assert inspect("https://en.wikipedia.org/wiki/Example_phone", render)["reason"] == "logo_like"

0 commit comments

Comments
 (0)