Проект: Разработка CMS для фотографов  Публичный пост
2 сентября 2023  1106
Разработка CMS для фотографов
https://github.com/endlessnights/photogallery

Расскажите о себе и сути проекта?

Всем привет! Я часто фотографирую как на зеркалку, так и на телефон и для меня всегда было проблемой где размещать свои фотографии. Уже на этом моменте у читателя в голове сразу всплывет несколько вариантов: Instagram, Tilda, Wordpress.
Обо всём по порядку, но начну с самого важного - я хотел бы иметь все свои данные "под рукой", то есть, внезапно, Self Hosted.
Instagram - хорошая площадка с легким продвижением, но их правила это что-то своеобразное, меня там забанили полгода назад за несколько (10-15) неудачных авторизаций и даже данные не получилось сохранить, благо на всё у меня были бекапы. Больше к Instagram я не вернусь. Tilda - опять же это SaaS, за домен плати (это понятно), за их сервис плати. Он удобен, но опять же не Self-hosted. WordPress и другие CMS - действительно self-hosted решения, но обычно они громоздкие в своем исполнении, и, только что развернутый WordPress из коробки глючит и загружает коробочную единственную статью 8-10 секунд на локальном сервере, а что будет на проде... Я проверял - админка грузится по полминуты, страницы с фотками 40-60 фоток - под минуту грузятся и это со всякими плагинами на кэширование и прочее.

Как появилась идея? Что вдохновило?

Возможно я раздуваю из мухи слона, но мне захотелось сделать свою CMS для фотографов. Ключевые требования к CMS, которые я себе поставил:

  1. Self-hosted.
  2. Возможность загружать за раз много фотографий.
  3. С помощью drag&drop изменять порядок фото в альбомах.
  4. Доставать из Фото данные EXIF и возможность их править.
  5. Кастомизация сайта: логотип, шрифты, цвета, шаблоны альбомов, возможность редактировать код шаблонов.

Что вошло в прототип и сколько времени на него было потрачено?

Моя первая попытка не увенчалась успехом, но я всё равно пользовался данным решением в течении 1-1.5 лет:
https://github.com/endlessnights/PhotoSite
В середине июля в чате Вастрик.Фотки кто-то начал обсуждение кто где хранит или показывает свои фотки - у кого-то Tilda, у кого-то статик сайт самопис (у меня в том числе так было длительное время), а кто-то в инсте или телеграм-канале публикует свои работы. Там же и я предложил собраться силами и написать решение для фотографов - проект фото сайта, CMS.
https://vas3k.club/user/tkf/ создал отдельный чатик и работа началась.
На весь проект от зарождения идеи до готового рабочего проекта ушел всего 1 месяц с небольшим. В 20-х числах августа проект был завершен. Время от время я нахожу мелкие баги и чиню их.
https://vas3k.club/user/tkf/ и https://vas3k.club/user/TiraelSedai/ мне очень помогло советами, подсказками, решениями каких-то сложностей с бэком и фронтом.
Прототипом стал мой же сайт, который я, думаю, около года назад переписал на статику, используя CSS-фреймворк UIkit, там был уже готовый дизайн и я старался перенести его на рельсы новой CMS.

Какой технологический стек вы использовали? Почему?

Я использовал Django - Python фреймворк, так как я с ним давно знаком (с 2020). Я старался привести к минимуму используемые внешние либы, чтобы, в случае чего опираться на свой код, а не чужой, поэтому в моем проекте из сторонних либ только envparse о котором весною мне рассказала https://vas3k.club/user/nbirdie/ и Pillow - для обработки и показа фотографий.
Благодаря ChatGPT удалось сделать очень многое за короткие сроки, так как я не умею в JavaScript, а, например следующие фичи требуют знания JS:

  1. Изменение порядка фотографий в альбоме
  2. Изменение порядка пунктов меню, иконок соц. сетей

А благодаря Ajax изменения в большинстве случаев сохраняются автоматически, не нужно нажимать никакие кнопки.
Так как, можно считать, был единственным разработчиком, споров о фронте никаких не было. Я выбрал UIkit, так как я тоже с ним прежде немного работал.
Очень многое возложено но Pillow либу, так как у CMS из коробки включено сжатие загружаемых изображений (в настройках можно изменить целевое разрешение и качество в % как для больших изображений, так и для превью.
База данных - SQLite, в будущем, в последующих итерациях добавим возможность выбирать между PSQL и SQLite, так как база SQLite создается из коробки, а PSQL нужно отдельно разворачивать, но я придумаю, как это автоматизировать тоже.

С какими самыми неожиданными трудностями пришлось столкнуться?

Не скажу, что это трудности, но честно говоря я ожидал, что интереса к проекту с чата Вастрик.Фотки будет больше, так как обсуждение было бурным несколько дней, а в чат разработки вступило всего 10 человек, где было всего 2 активных участника + я.
Я думал, что найду Python-разработчиков или фронтендеров в команду, чтобы распределить разработку, но вышло всё как всегда - я делал всё один + получал советы, подсказки, ссылки; повторюсь, https://vas3k.club/user/tkf/ и https://vas3k.club/user/TiraelSedai/ мне очень помогли в этом деле.
Повторюсь, с JS очень много плясок было, так как я с ним дальше вытянутой руки, пришлось осваивать как работают его переменные, вникать в Ajax.
Еще сложностью было - в чате разработки так и не пришли к единому мнению как должны выглядеть Главная страница и страница О себе, поэтому я решил сделать шаблоны для них и добавить возможность редактировать эти шаблоны или писать свои - имея HTML-редактор.
Первым делом я нашел WYSIWYG-конструктор сайтов GrapeJS и пытался его адаптировать под свой Django-проект, получилось хорошо, но работали не все компоненты, в итоге я создал отдельную репу под это дело, кто-нибудь когда-нибудь это раскопает:
https://github.com/endlessnights/django-grapejs

Также, я ставил тяжеловесный Ckeditor, но не понял, как по умолчанию показывать source-code-редактор, а не wysiwyg-редактор. Позже, тоже отказался от него.
В чате предложили несколько вариантов, в том числе CodeMirror и я остановился на нем. Реализация тоже не очевидная, но это работает, есть баги редкие до сих (как исправить не знаю), уточню, они очень редкие и на пользовательский опыт не сильно повлияют:

Также, после деплоя на рабочий сервер с Nginx обнаружилось, что у Nginx имеются ограничения на размер загружаемых файлов и таймауты из-за чего по умолчанию не получалось загружать сразу много изображений 15-20 проходили нормально, а если загружалось 30-40-60 за раз, то появялялась ошибка.
Добавлением следующего кода в файл конфигурации Nginx решил проблему:

    client_max_body_size 300M;
    proxy_read_timeout 300;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;

Еще были сложности с удалением файлов как при одиночном удалении изображений из альбома, так и удаление скрытых изображений или сразу всех. При загрузке каждого файла на диск записывается оригинальный файл (так как есть флажок, чтобы Pillow не сжимал качество, а использовал оригинальные загруженные изображения), Pillow создавал файл _resized и _thumbnail для сжатого полноэкранного изображения и для превью (в настройках правится целевое разрешение и качество в %), итого под каждое изображение у нас 3 файла. Не бойтесь, сжатые фотки весят сильно меньше оригинальных. Например, Оригинальный файл jpeg весит 13 Мбайт, сжатый полноэкранный 200-300 кб, а превью - 30-60 кб.
При удалении изображений удалялись только превью и полноэкранные, а сами оригинальные файлы не удалялись и поэтому создал дополнительное поле, которое заполняется Django автоматически (пользователь этого не видит) путем до оригинального файла, что позволяет в дальнейшем при удалении изображений подчищать за ними все остатки. Пример функции, которая удаляет одно выбранное изображение из альбома:

@login_required
def delete_image(request, image_id):
    image_obj = Image.objects.get(id=image_id)
    image_path = os.path.join(global_settings.MEDIA_ROOT, str(image_obj.image))
    thumbnail_path = os.path.join(global_settings.MEDIA_ROOT, str(image_obj.thumbnail))
    src_image_path = os.path.join(global_settings.MEDIA_ROOT, str(image_obj.src_image))
    if os.path.exists(image_path):
        os.remove(image_path)
    if os.path.exists(thumbnail_path):
        os.remove(thumbnail_path)
    if os.path.exists(src_image_path):
        os.remove(src_image_path)
    image_obj.delete()
    return redirect(request.META['HTTP_REFERER'])

Сколько потратили и заработали? Есть идеи как это можно монетизировать?

Ничего не потратил и ничего не заработал, это же Open Source проект. Вы можете мне поставить звездочек на репе и я получу ачивку. Но если серьезно, я думаю этот проект может смело превратиться в SaaS, такой как тот же wfolio, но опыт с моим SaaS-стартапом многое мне поведал - сначала ищи клиентов, а потом делай проект. Правда, это не совсем про меня, так как я делаю проекты в первую очередь для своего удобства, я ими пользуюсь по назначению, а в SaaS они вытекают, потому что могут. Тут же надо делать всё по-нормальному, если превращать в SaaS - хотелось бы собрать команду - UI/UX-специалиста, веб-дизайнера/фронтендера хотя бы и Маркетолога - кто разбирается в продажах продукта.

Что получилось

По итогу имеем следующий функционал:

  1. Создание и управление альбомами
  2. Загрузка изображений и/или связывание с YouTube-видео
  3. Изменение альбомов и изображений (изменение порядка, настройка колонок, анимации)
  4. Настройка видимости альбомов
  5. Выбор между видами галереи сетки (grid) или кирпичной кладки (masonry)
  6. Обработка загруженных изображений (создание миниатюр и изображений в полном размере для галерей с полноэкранным просмотром) путем настройки разрешения и качества
  7. Настройка меню (изменение порядка и переименование элементов)
  8. Интеграция ссылок на социальные сети с иконками Font Awesome, с возможностью редактировать их порядок, ссылки, названия и иконки
  9. Извлечение EXIF-данных из изображений и их отображение в режиме просмотра Lightbox
  10. Доступ к географической информации и координатам из EXIF, отображаемых на Google Maps
  11. Редактирование настроек сайта, включая загрузку логотипа, настройку метаданных и стилизацию шрифта для подписей и текста
  12. Редактирование EXIF-данных напрямую
  13. Timeline, как у Google Photos, представляющей все изображения на сайте, организованные и названные по годам их съемки
  14. Перевод административного раздела сайта; в данный момент поддерживает английский и русский языки, с возможностью изменения этого в разделе "Общие настройки" раздела "Настройки сайта"
  15. Редактор шаблонов с подсветкой синтаксиса (HTML, CSS, JS) для главной страницы и страницы "Обо мне", работающим на CodeMirror. Можно использовать встроенные и пользовательские теги Django с фильтрами в редакторе шаблонов.
  16. А также, автоматическое создание учетной записи после запуска проекта.

Я развернул проект у себя и теперь использую его в кач-ве своего сайта с фотографиями: https://endlessnights.ru

Теперь, в том числе участники клуба, которые занимаются фотосъемкой имеют еще один вариант размещения своих работ в Интернете (или локально).

Скриншоты и подробности по развертыванию по ссылке: https://github.com/endlessnights/photogallery
Если вы Маркетолог, UI/UX-специалист или фронтенд-разработчик, напишите в лс, если готовы сделать из этого хороший SaaS.

Планы на будущее

В данный момент CMS принимает любые форматы изображений, но генерирует только JPEG на выходе для сжатых изображений. Они маленькие (занимают мало места на диске), но могли бы быть еще меньше. Планирую переделать пересжатие в Webp, так как выходные файлы занимают еще меньше места, чем такого же качества JPEG.
Также, у меня есть 180-360 панорамы и хотелось бы добавить возможность их поддержки проектом, чтобы загруженные панорамы можно было крутить, вращать в разные стороны.

Какой совет вы бы сами могли дать идущим по вашим стопам?

Если хочешь сделать хорошо, сделай это сам.

Связанные посты
9 комментариев 👇

Странно, что не нашлось подходящего плагина к wordpress для управления фотографиями. Даже в Orchard CMS под dotnet довольно мощный Media Manager.

  Развернуть 1 комментарий

@musuk, Я вначале поста писал, почему пришлось отказаться от WordPress. Про Orchard CMS ничего не слышал; я так понял он на .net написан, я в этом не разбираюсь, поэтому, если мне нужно будет что-то кастомное, то придется много страдать, поэтому был выбран путь Python.

  Развернуть 1 комментарий

@legeminus, Так я ж говорю про какой-нибудь сторонний плагин медиаменеджера, а не тот, который есть из коробки.
Мой посыл в том, что медиаменеджеры должны быть для любой CMS, и даже если хочется кастомных функций, то можно расширять уже готовый filebrowser.
Но с другой стороны, своё писать интереснее, чем в чужом коде ковыряться.

  Развернуть 1 комментарий

Пара советов:

  • Перевести загрузку и обработку фото на очереди.

  • Не храните файлы на диске сервера, добавьте сразу загрузку в S3 хранилище.

  Развернуть 1 комментарий

@ben_yazi, спасибо за советы, пойду копать celery, пока что для меня это темный лес.
Насчёт S3 - тоже согласен, но добавлю позднее как опцию.
Сейчас нужно сосредоточится на avif в первую очередь. Очереди сразу после avif и наконец хранилища данных.

  Развернуть 1 комментарий

Вот тут уже рассказывали про довольно классный immich.app, есть ли у него какие-то минусы кроме фатального недостатка?

  Развернуть 1 комментарий

Сейчас ищу CMS для ретушера, для создания портфолио. Тильда оказалась шляпой, сейчас делаю PoC на Wordpress.
Из интересного нашел вот что:
https://vigbo.com/ - CMS + создание сайтов для фотографов
https://wfolio.ru/ - SaaS для фотографов, продюсеров, ретушеров с облаком на 1Тб и интересными фичами

  Развернуть 1 комментарий

😱 Комментарий удален его автором...

  Развернуть 1 комментарий
Vlad Zaitsev Architect & Product Owner 3 июня в 15:30

Еще очень нужна функция "загрузить тыщу сырых фото, чтобы модель поставила лайки на те, что ей нравятся".

  Развернуть 1 комментарий

Посмотри в сторону https://imgproxy.net или аналогов для обработки — возможно ничего и не придется обрабатывать у себя

  Развернуть 1 комментарий

😎

Автор поста открыл его для большого интернета, но комментирование и движухи доступны только участникам Клуба

Что вообще здесь происходит?


Войти  или  Вступить в Клуб