Migrate a vBulletin 4 forum to Discourse

Да, они преобразуются. Я напишу вам завтра по электронной почте!

3 лайка

Чтобы разблокировать личные сообщения, нужно достичь уровня доверия 1, но вы пока не провели достаточно времени за чтением тем здесь, чтобы этого добиться.

4 лайка

Привет, я работаю в контейнере Docker (DigitalOcean) и пытаюсь импортировать MyBB (я знаю, что этот учебник для Vbulletin, но с Gemfile всё аналогично). Я застрял на этапе bundle install:

Здравствуйте,
Мы пытались импортировать vBulletin 3.8 в Discourse. Этот скрипт работает нормально с базой данных объемом 300 МБ, примерно 40 000 пользователей и 60 000 сообщений. Однако в конце процесса импорта мы столкнулись с проблемой кодировки.

  • Наш vBulletin 3.8 использует кодировку: latin1
    ----> при выполнении скрипта импорта MySQL 5.6 в Docker-контейнере Discourse также настроен на кодировку UTF-8,
  • Скрипт импорта принудительно преобразует данные в UTF-8,
    поэтому в конце процесса импорта форум Discourse отображает данные с ошибкой кодировки UTF-8. Это выглядит как на изображении ниже.
  1. До импорта, vB 3.8

  2. После импорта в Discourse

Мы попробовали:

  • Преобразовать кодировку в vB 3.8 в UTF-8 перед запуском скрипта импорта
  • Протестировать эту базу данных vB 3.8 на новом сервере MySQL, где текст отображается нормально, без ошибок кодировки.
    Таким образом, не могли бы вы дать какие-либо рекомендации в этом случае?

Благодарим за любую помощь по этому вопросу (также приносим извинения за свой английский, если вам трудно понять).

1 лайк

Вот фрагмент кода, который помог мне решить похожую проблему:

    ### Кодировка WIN1252
    win_encoded = ''
    begin
      win_encoded = raw.force_encoding('utf-8').encode("Windows-1252",
                            invalid: :replace, undef: :replace, replace: ""
                           ).force_encoding('utf-8').scrub
    rescue => e
      puts "\n#{'-'*50}\nWin1252 не сработал для \n\n#{raw}\n\n"
      win_encoded = ''
    end
    raw = win_encoded
5 лайков

Вы спасли мне жизнь.
Для быстрого решения я попробовал скрипт конвертации из темы на форуме: Migrate a phpBB3 forum to Discourse - #540 by gerhard. Он помог быстро исправить проблему с кодировкой базы данных, и теперь всё работает как по маслу.
Огромное спасибо за совет.

3 лайка

Кто-нибудь мигрировал с помощью импортера vBulletin 5? Я, возможно, воспользуюсь им в будущем, и хотел бы узнать, использовался ли он уже безупречно.

2 лайка

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

3 лайка

У меня есть дамп базы данных vb5, содержащий вложения. Можно ли импортировать их в Discourse, или мне нужны все вложения в виде файлов?

Тоже запутался в этом вопросе. Куда именно в папке Discourse нужно скопировать файлы вложений? :thinking:

2 лайка

Привет снова,

Насколько я понимаю, вложения из базы данных будут работать, так как они обрабатываются так же, как аватары, которые тоже хранятся в базе данных.

Мой импорт идет хорошо, но на 91% импортированных постов возникла ошибка :weary_face:

importing posts...
  1425149 / 1564573 ( 91.1%)  [1040 items/min]  Traceback (most recent call last):
        14: from script/import_scripts/vbulletin5.rb:726:in `<main>'
        13: from /home/canapin/discourse/script/import_scripts/base.rb:47:in `perform'
        12: from script/import_scripts/vbulletin5.rb:49:in `execute'
        11: from script/import_scripts/vbulletin5.rb:300:in `import_posts'
        10: from /home/canapin/discourse/script/import_scripts/base.rb:862:in `batches'
         9: from /home/canapin/discourse/script/import_scripts/base.rb:862:in `loop'
         8: from /home/canapin/discourse/script/import_scripts/base.rb:863:in `block in batches'
         7: from script/import_scripts/vbulletin5.rb:320:in `block in import_posts'
         6: from /home/canapin/discourse/script/import_scripts/base.rb:508:in `create_posts'
         5: from /usr/local/rvm/gems/ruby-2.6.5/gems/rack-mini-profiler-2.0.4/lib/patches/db/mysql2.rb:8:in `each'
         4: from /usr/local/rvm/gems/ruby-2.6.5/gems/rack-mini-profiler-2.0.4/lib/patches/db/mysql2.rb:8:in `each'
         3: from /home/canapin/discourse/script/import_scripts/base.rb:509:in `block in create_posts'
         2: from script/import_scripts/vbulletin5.rb:321:in `block (2 levels) in import_posts'
         1: from script/import_scripts/vbulletin5.rb:450:in `preprocess_post_raw'
script/import_scripts/vbulletin5.rb:450:in `gsub': invalid byte sequence in UTF-8 (ArgumentError)

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

1 лайк

Кто-то предлагал способы использования rescue для решения таких проблем, так что вы можете вернуться и найти это (я не помню, было ли это в этой теме или в другой). Вы можете добавить put в блок rescue, чтобы вывести id и/или текст, вызвавший проблему.

У вас проблема с кодировкой.

Я использовал это при похожем импорте (думаю, вы добавите это в preprocess_post_raw):

    begin
      win_encoded = raw.force_encoding('utf-8').encode("Windows-1252",
                            invalid: :replace, undef: :replace, replace: ""
                           ).force_encoding('utf-8').scrub
    rescue => e
      puts "\n#{'-'*50}\nWin1252 failed for \n\n#{raw}\n\n"
      win_encoded = ''
    end
3 лайка

Привет,
Я модифицировал импортер и добавил ваш скрипт следующим образом:

  def preprocess_post_raw(raw)
    return "" if raw.blank?
    begin
      win_encoded = raw.force_encoding('utf-8').encode("Windows-1252",
                            invalid: :replace, undef: :replace, replace: ""
                           ).force_encoding('utf-8').scrub
    rescue => e
      puts "\n#{'-'*50}\nWin1252 failed for \n\n#{raw}\n\n"
      win_encoded = ''
    end
    # decode HTML entities
    raw = @htmlentities.decode(raw)

    # fix whitespaces
    raw = raw.gsub(/(\r)?\n/, "\n")
      .gsub("\t", "\t")

Ошибка некорректной последовательности байтов в UTF-8 возникает на этом участке: raw = raw.gsub(/(\r)?\n/, "\n") .gsub("\t", "\t").

Затем я снова запустил импортер. Хотя он пропускает уже импортированные данные, потребовалось около 6 часов, чтобы дойти до сообщения, вызывающего ошибку, и ожидаемая информация для просмотра содержимого сообщения так и не была добавлена. :confounded_face: Есть какие-нибудь идеи, почему это происходит?

edit:

Скорее всего, именно это сырое содержимое сообщения приводит к ошибке:

I wonder if Billy is enjoying the parade.

Qwertyuiopasdfghjklzxcvbnm&#55356;&#57174;

Я попробую изменить скрипт импортера, чтобы он действительно пропускал предыдущие 1,4 млн сообщений. Пожелайте мне удачи. :crossed_fingers:

2 лайка

Я добавил параметр import_after во многие другие импортеры, чтобы позволить импортировать только последние данные. Вы можете посмотреть на другие примеры, чтобы увидеть, как я это сделал.

2 лайка

Привет,
Мне удалось импортировать почти все мои посты! Я вручную исправил несколько десятков и перезапускал импорт каждый раз, когда возникала новая ошибка UTF-8… :sweat_smile:

Теперь мне нужно импортировать вложения (которые хранятся в базе данных VBulletin), но это не работает:
Когда процесс начинается, потребление оперативной памяти резко возрастает в течение 10–20 секунд, и возникает следующая ошибка:

importing attachments...
Failed to create upload: Cannot allocate memory - grep
Fail

Моя оперативная память:

Я использую версию Discourse для разработки в подсистеме Ubuntu 18 на Windows 10, и у меня 16 ГБ оперативной памяти.

Вложения занимают 7 ГБ из 13 ГБ базы данных vBulletin.
Обратите внимание, что я использую импортер vbulletin5.

Проблема возникает из-за этого запроса:

    SELECT n.parentid nodeid, a.filename, fd.userid, LENGTH(fd.filedata) AS dbsize, filedata, fd.filedataid
      FROM #{DB_PREFIX}attach a
      LEFT JOIN #{DB_PREFIX}filedata fd ON fd.filedataid = a.filedataid
      LEFT JOIN #{DB_PREFIX}node n on n.nodeid = a.nodeid

Если я выполняю этот запрос в MySQL, оставшаяся оперативная память заполняется за несколько секунд.


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

Обходное решение:

Я добавил ограничение (LIMIT) и смещение (OFFSET) к SQL-запросу импортера. Я импортировал вложения, выбирая по 20 000 за раз:

    uploads = mysql_query <<-SQL
    SELECT n.parentid nodeid, a.filename, fd.userid, LENGTH(fd.filedata) AS dbsize, filedata, fd.filedataid
      FROM #{DB_PREFIX}attach a
      LEFT JOIN #{DB_PREFIX}filedata fd ON fd.filedataid = a.filedataid
      LEFT JOIN #{DB_PREFIX}node n on n.nodeid = a.nodeid
      LIMIT 20000 OFFSET 0
    SQL

Также я добавил exit в конце цикла uploads.each do |upload|, чтобы предотвратить продолжение работы скрипта импорта после импорта моих 20 000 вложений.

После импорта 10 000 вложений я редактирую скрипт (спасибо команде nano +353 ./scripts/import_scripts/vbulletin5.rb, которая открывает файл в нужной строке), чтобы увеличить смещение SQL-запроса (OFFSET) на 10 000, и снова запускаю импортер… И так делаю для всех моих 65 000 вложений.

Во время импорта вложений я столкнулся с несколькими ошибками и предупреждениями, включая:

  • W, [2020-08-20T12:05:37.402860 #31042] WARN -- : Bad date/time value "0000:00:00 00:00:00": mon out of range
  • Post for 490451 not found (полагаю, это старые «висячие» вложения?)
  • некоторые ошибки данных EXIF
  • Fail Эта ошибка меня озадачила и остановила скрипт импорта. Я проверил первое возникшее сообщение “Fail” и обнаружил, что вложение в форуме было повреждено (отсутствовало имя файла), поэтому я закомментировал инструкцию exit, чтобы импортер продолжал работу при «сбое», надеясь, что это ничего не сломает.
       puts "Fail"
       #exit

Также у меня была более раздражающая ошибка, которая прервала импорт:

1: from /usr/local/rvm/gems/ruby-2.6.5/gems/activerecord-6.0.3.2/lib/active_record/validations.rb:53:in `save!'
/usr/local/rvm/gems/ruby-2.6.5/gems/activerecord-6.0.3.2/lib/active_record/validations.rb:80:in `raise_validation_error':
Validation failed: Body is limited to 32000 characters; you entered 32323. (ActiveRecord::RecordInvalid)

К счастью, это была редкая ошибка, и я просто пропускал это вложение, пока не сталкивался со следующей аналогичной ошибкой. Это произошло, возможно, дюжину раз из общего числа 65 000 вложений. Я просто перезапускал скрипт импорта с другим смещением SQL-запроса.

1 лайк

Привет,
Я заметил, что пользовательское поле import_pass отсутствовало примерно у 400 из оставшихся 27 000 пользователей (я очистил 154 000 неактивных пользователей).\n
Не знаете, почему так?

Форум был перенесён с phpBB на vBulletin в мае. Может ли это быть связано с этим?

Я не буду пытаться «исправить» это и импортировать пароли для этих 400 пользователей (если только нет простого способа сделать это…), и это не является большой проблемой, поэтому меня интересует это больше из любопытства.

1 лайк

Всем привет,

Импортированные изображения имеют неверное соотношение сторон, если я не пересобираю посты. Я хотел бы найти способ получить правильное соотношение (например, во время импорта), не прибегая к пересборке.

Более подробное описание проблемы:

Насколько я понимаю, импортированные посты не проходят процедуру «выпечки» (baking) при создании соответствующего поста в Discourse (хотя поле cooked каким-то образом генерируется), поэтому импорт постов происходит намного быстрее, чем выпечка существующих постов Discourse.

Моя проблема в том, что у импортированных изображений неверное соотношение ширины и высоты.

Пример необработанного текста Discourse, связанного с импортированным изображением:

![SH-MUniFrame.JPG|600x800](upload://6Li1nnjbA8zDz6YJ3FqeYHV5zXK.jpeg)

Содержимое поля «cooked»:
<img src="https://d11a6trkgmumsb.cloudfront.net/original/3X/0/3/0379f53ed8221730ccb31807238e9c46e9fe1d37.jpeg" alt="SH-MUniFrame.JPG" data-base62-sha1="6Li1nnjbA8zDz6YJ3FqeYHV5zXK" width="517" height="500" class="d-lazyload">

Как изображение отображается в посте:

Вот оригинальное изображение: https://d11a6trkgmumsb.cloudfront.net/original/3X/f/7/f73a0ae8594219dd5a1620e59b3c17f9b02b1583.jpeg

Размер оригинального изображения из базы данных vBulletin:

select width, height from filedata where filedataid = 76237
+-------+--------+
| width | height |
+-------+--------+
|   600 |    800 |
+-------+--------+

Я полагаю, что атрибут высоты ограничен настройкой Discourse, которая устанавливает максимальную высоту 500 пикселей, поэтому в атрибуте высоты тега <img> указано то же значение. Атрибут ширины тега <img> каким-то образом изменён с 600 до 517, но я не могу понять, как и почему.

Та же проблема наблюдается у старых изображений, у которых в полях вложений vBulletin значения ширины и высоты равны 0. У них также неверное соотношение высоты и ширины. Не знаю, используются ли эти значения действительно при импорте.

Проблема решается пересборкой (пересозданием HTML) поста. После этого изображение будет правильно изменено в размерах, и добавится просмотрщик изображений. Но у меня 1,6 млн постов, и я предпочёл бы избежать пересборки всех из них.

Быстрым решением могло бы быть применение следующего CSS на моём Discourse:

.cooked img:not(.emoji) {
    height: auto;
    width: auto;
}

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

Есть ли у кого-нибудь идеи, как обеспечить правильное соотношение сторон у импортированных вложений?

Подозреваю, что это потому, что вы не дали им «отстояться» после импорта. Не могу представить способ решить проблему без повторной обработки постов. Возможно, вам стоит обработать заново только сломанные посты, а не все сразу?

1 лайк

Они должны готовиться автоматически со временем после импорта? Начиная с последнего или самого первого созданного поста?

Это, впрочем, не большая проблема. Если они не готовятся автоматически, я, вероятно, запущу перевыпечку всех постов и буду терпеливо ждать, хотя признаю, что несколько дней назад я прочитал этот пост, и он меня немного напугал: My journey into a massive posts rebake job. У меня тоже есть вопросы по этому поводу, но я задам их в соответствующей теме. :blush:

Хм, да, похоже, это мой код. Извините за это. :confused:

Это должно выглядеть следующим образом:

   batches(BATCH_SIZE) do |offset|
       (SQL-код)
        LIMIT #{BATCH_SIZE}
        OFFSET #{offset}
        (Другой код)
    end
1 лайк

Просто увеличьте настройку сайта max post length перед импортом.

2 лайка