Здравствуйте, я загружаю много (как посмотреть) фото (и не только) в Wikimedia Commons. Вместе с Википедией, это важный сервис, особый: некоммерческий, тоже живет на донаты, без рекламы и платных аккаунтов, всё содержимое в свободных лицензиях. Базовый путь загрузки - через веб клиент, который сложный, это не в Фейсбук перетянуть фото. Экосистема, инфраструктура, комьюнити огромно, есть десяток инструментов загрузки. И внезапно, за вечер, я сделал, по моему мнению, один из лучших инструментов, о котором мечтал годами. Получилось так быстро потому что это скрипт для gThumb, который использует официальное SDK Pywikibot на Питоне, и библиотека для чтения/записи IPTC тегов - где указываются категории, категории это важно - Коммонс это не помойка, при загрузке и после ребята стараются систематизировать артефакты, у каждого файла может быть много категорий.

gThumb, слева окно с тегами
gThumb, слева окно с тегами

История такова, что перед созданием этого скрипта, я долго пытался починить другой хороший инструмент загрузки - плагин dtMediaWiki, написанный на Lua, для Darktable. Но в итоге столкнулся с дефектом самого Darktable, который похоже лишь на моей машине - segmentation fault после каждой загрузки. Да и не нравилось мне что Darktable работает с копиями фотографий, которые нельзя переименовать в оригинальном месте.

Увидел что в gThumb есть расширения, на C, подумывал реализовать на нём, месяцев за шесть, ведь с этим языком опыта мало. А потом обнаружил что можно дергать внешние скрипты, написанные на любом языке - им можно передавать путь фоток. Попробовал написать прототип - и внезапно оказалось хорошо. До софта мечты не хватает лишь подсказок при указании категорий, как в браузере, ну не велика печаль; поиск категорий для Wikimedia Commons занимает много времени, и скопировать из другого окна её название - не проблема.

Вот текущее состояние всего этого скрипта:

#!/usr/bin/env python3

import sys
import os

import string

from iptcinfo3 import IPTCInfo

import pywikibot
from pywikibot.specialbots import UploadRobot

pywikibot.config.put_throttle = 0  # Set to 0 to disable throttling

# print('pywikibot.config.max_retries:', pywikibot.config.max_retries)

# https://pypi.org/project/IPTCInfo3Plus
info = IPTCInfo(sys.argv[1])

categories = ''
for val in info['keywords']:
    if val.startswith(b'Category:'):
        categories += '[[' + val.decode('utf-8').replace('_', ',') + ']]\n'
categories = categories.rstrip('\n')

site = pywikibot.Site('commons', 'commons')

username = site.username()

description = info['caption/abstract'].decode('utf-8') if info['caption/abstract'] else ''

description = string.Template('''=={{int:filedesc}}==
{{Information
|description={{en|1=$description}}
|Source         = {{own}}
|Author         = [[User:$username|$username]]
}}
=={{int:license-header}}==
{{self|CC-BY-4.0}}
$categories
[[Category:Uploaded with gThumb script]]''').substitute(locals())

filename = os.path.basename(sys.argv[1])
print('filename:', filename)

def post_processor(old: str, new: str | None) -> None:
    info['source'] = 'https://commons.wikimedia.org/wiki/File:' + filename.replace(' ', '_')
    info['keywords'].append('uploaded')
    info.save()

print(description)

# https://doc.wikimedia.org/pywikibot/master/api_ref/pywikibot.specialbots.html#specialbots.UploadRobot.run
bot = UploadRobot(
    sys.argv[1],
    description=description,
    keep_filename=True,
    ignore_warning=True,
    target_site=site,
    summary='Uploaded through gThumb with https://gitlab.com/vitaly_zdanevich/upload_to_commons_with_categories_from_iptc',
    always=True
)

bot.post_processor = post_processor

def global_exception_handler(*args):
    exc_type, exc_value, exc_traceback = sys.exc_info()
    # print(vars(exc_value))
    # print('code:', exc_value.code)
    if exc_value.code == 'fileexists-no-change':
        print('SHA256 of this image already exists, do nothing')

pywikibot.exception = global_exception_handler

bot.run()

print('\n----------\n')

Меньше сотни строк, а получился такой полезный инструмент.

Скрипт принимает путь с фото (отдельный вызов для каждого файла), вынимает IPTC теги начинающиеся на Category: и описание тоже берёт из мета-тега, и загружает. One-by-one, не параллельно - чтобы не удариться в лимитеры, что у меня уже происходило даже при последовательной загрузке. Если столкнётесь с этим - у Wikimedia можно попросить расширения прав. Использовать скрипт можно и без gThumb, либо из любой другой программы. Прекрасно. После успешной загрузки - ставит в мета-данные линк, и добавляет тег uploaded, для наглядности.

gThumb, и другие программы, могут вызывать скрипты, что открывает возможности по расширению. Например, можно не с нуля разработать своё приложение, а сделать плагином/экстеншеном для существующей программы. Например, внешняя автоматическая обработка фоток, загрузки/копирования, анализ, заполнение мета-данных.

На радостях написал ещё один скриптик, ещё более простой - читает GPS и открывает OpenStreetMap/GoogleMaps/YandexMaps карту для фото - путём формирования простого линка:

#!/usr/bin/env python3

import sys
from fractions import Fraction
import webbrowser

import exifread


def convert_to_decimal(coord):
    deg = float(coord.values[0])
    min = float(coord.values[1]) / 60
    sec = float(Fraction(coord.values[2])) / 3600
    return deg + min + sec

with open(sys.argv[1], 'rb') as file_handle:
    tags = exifread.process_file(file_handle)
    for tag, value in tags.items():
        if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'EXIF MakerNote'):
            if tag == 'GPS GPSLatitude':
                lat = value
            if tag == 'GPS GPSLongitude':
                lon = value
            if tag == 'GPS GPSLatitudeRef':
                lat_ref = str(value)
            if tag == 'GPS GPSLongitudeRef':
                lon_ref = str(value)

lat_dec = convert_to_decimal(lat)
lon_dec = convert_to_decimal(lon)

if lat_ref in ['S']:
    lat_dec = -lat_dec
if lon_ref in ['W']:
    lon_dec = -lon_dec

if len(sys.argv) > 2:
        if sys.argv[2] == 'google':
            webbrowser.open(f'https://www.google.com/maps?q={lat_dec},{lon_dec}')
        else:
           webbrowser.open(f'https://yandex.com/maps/?pt={lon_dec},{lat_dec}&z=18')
else:
    webbrowser.open(f'https://www.openstreetmap.org/?mlat={lat_dec}&mlon={lon_dec}&zoom=18')

Пишите ваши полезные скрипты для gThumb, анонсируйте их в разных релевантных площадках, помните про SEO - пишите README, используйте теги в Gitlab/Github чтобы можно было найти. Можете и мне лично писать о вашем новом скрипте, я порадуюсь и возможно установлю себе :)

Ещё одна цель этой статьи - напомнить вам о существовании Wikimedia Commons, где уже 120 миллионов артефактов, включая даже 3D модели, которая будет рада принять ваши свободные фото, видео (в свободных кодеках), аудио. Безлимитное место для фото, public only, где комьюнити будет бережно помогать вам каталогизировать и описывать ваши пиксели. А даже если и без Commons - отсканируйте наконец свои старые семейные альбомы, чтобы не пропали.

А ещё, чем я иногда тоже в меру сил занимаюсь - пишу людям которые уже сделали много фотографий, и прошу разрешения загрузить в Wikimedia Commons, чтобы остались, ведь я уже хорошо знаю как пропадают сайты и личные хранилища, и люди внезапно смертны. Это обращение и к вам - если у вас уже есть гигабайты фотоснимком, или вы знаете такого человека - напишите мне пожалуйста, либо можете сами заняться этим архивационным проектом.

Комментарии (2)


  1. dartraiden
    09.06.2025 08:14

    Стоит, всё же, учитывать, что Склад это не просто хостинг (файлы должны иметь образовательную ценность) и, размещая там файлы, нужно быть уверенным, что у вас есть право это делать (например, невозможно легально опубликовать фото из семейного архива, сделанное неизвестным фотографом, скажем, в советском фотоателье).


  1. pythonist1234
    09.06.2025 08:14

    О, я как раз несколько месяцев назад с парой человек заливал на Склад 55+ тысяч футбольных фотографий, все тщательно разложенные по категориям (половину дерева сами сделали, наверное) и связанные с Викиданными) И вскоре похожее продолжим.