Russian Qt Forum
Май 05, 2024, 09:51 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: HowTo: создание .torrent файлов в Windows (Qt+MinGW+libtorrent)  (Прочитано 21362 раз)
XpycT
Гость
« : Март 01, 2010, 21:08 »

Примерно пол года назад понадобилось реализовать в своем проекте возможность создания .torrent файлов. Для этой цели выбрал библиотеку libtorrent-rasterbar. Но в отличии от msvc, сборка под MinGW оказалась довольно не приятной (пришлось править код самой библиотеки).
Старый вариант можете почитать >>> тут <<<

Итак, для этого нам понадобится:
1) Qt 4.5.x и выше
2) Boost 1.42.0 Src[скачать]
3) Libtorrent 0.14.9 Src[скачать] (лучше с SVN)
Прим.: На время написания моя конфигурация была windows 7, Qt 4.6.2, gcc 4.4.0, boost 1.42.0, libtorrent из SVN (v0.15)

Первое что делаем, это распаковываем boost и libtorrent куда вам удобнее. В моем случае это:
D:\boost_1_42_0\
D:\SVN\3rdPartyLibs\libtorrent\


Настройка BOOST

Теперь нам надо добавить 2 переменные среды,
Код
Bash
set BOOST_BUILD_PATH=D:\boost_1_42_0\tools\build\v2
set BOOST_ROOT=D:\boost_1_42_0
далее переходим в каталог D:\boost_1_42_0\tools\jam\src\ и запускаем build.bat с параметром mingw
Код
Bash
build.bat mingw
после чего в данном каталоге появится файл bjam.exe в подкаталоге bin.*, который надо скопировать в каталог, входящий в переменную PATH (например в c:\windows\system32).
Далее откройте блокнотом файл D:\boost_1_42_0\tools\build\v2\user-config.jam и раскомментируйте  нужный компилятор. В нашем случае меняем
Код
Bash
# using gcc ;
на
Код
Bash
using gcc ;
С boost'ом закончили, теперь переходим к нашему libtorrent.

Настройка LIBTORRENT

В отличии от предыдущего варианта, тут все сводится только к набору ключей при сборке.Полный список ключей компилятора можете найти на сайте библиотеки в разделе build configurations Так как мы не хотим делать полноценный клиент BitTorrent сетей, а использовать только создание торрент-файлов, то нам вполне подойдет следующий вариант.
Создаем в корне директории libtorrent (D:\SVN\3rdPartyLibs\libtorrent\) файл build.bat, в котором прописываем следующее:
Код
Bash
bjam gcc release link=static runtime-link=static boost=source dht-support=off need-librt=no geoip=off upnp-logging=off character-set=ansi

После запуска и полной компиляции, в корне директории Libtorrent в ./bin появятся поддиректории с именами ключей компилятора, в конце которых будет лежать готовая библиотека libtorrent.lib. (Для удобства вы можете вынести ее в корень каталога библиотеки, но я буду использовать путь по умолчанию.)
После того как вы собрали библиотеку - можете проверить ее на стандартных примерах в каталоге examples. Для этого просто перейдите в эту папку и вызовите:
Код
Bash
bjam gcc release link=static boost=source
Если примеры собрались без ошибок, тогда можно приступать к настройке проекта, если же были ошибки при сборке - посмотрите не пропустили ли вы что-то.

Настройка проекта

Создаем новый проект, открываем *.pro и добавляем в него
Код
C++ (Qt)
INCLUDEPATH += . \
   D:/SVN/3rdPartyLibs/libtorrent/include \ # путь к инклудам libtorrent
   D:/SVN/3rdPartyLibs/libtorrent/zlib \ # путь к zlib (есть в каталоге libtorrent)
   D:/boost_1_42_0 # путь к boost
CONFIG += static # так как библиотеку собирали в static
win32:LIBS += -L"D:\SVN\3rdPartyLibs\libtorrent\bin\gcc-mingw-4.4.0\release\boost-source\character-set-ansi\dht-support-off\link-static\runtime-link-static\threading-multi" \ # каталог где лежит libtorrent.lib
   -L"D:\boost_1_42_0\bin.v2\libs\system\build\gcc-mingw-4.4.0\release\boost-source\character-set-ansi\dht-support-off\link-static\threading-multi" \ # каталог c libboost_system-mgw44-mt-1_42.lib, который создался при сборке libtorrent
   -L"D:\boost_1_42_0\bin.v2\libs\filesystem\build\gcc-mingw-4.4.0\release\link-static" \ # каталог c libboost_filesystem-mgw44-1_42.lib. Нужен только для сборки примера (смотрите пример использования.)
-llibtorrent -llibboost_system-mgw44-mt-1_42 -lws2_32 -llibboost_filesystem-mgw44-1_42

Настройка проекта закончена. В примерах библиотеки libtorrent есть make_torrent.cpp, где показано как производится создание .torrent файлов.

Пример использования

На случай, если у Вас все же не получилось импортировать пример создания .torrent файлов в Qt, даю часть кода, выдернутого из моего проекта.
Только для его сборки вам понадобится дополнительно собрать из boost'a filesystem.
Для этого перейдите в каталог D:\boost_1_42_0\libs\filesystem\build\ и выполните там
Код
Bash
bjam gcc release link=static
После этого подправьте пути к библиотекам в create_torrent.pro и пересоберите проект.

В результате получите нечто похожее на uTorrent/BitTorrent:


PS. Файл примера частично основан на qbittorent, с измененным интерфейсом и некоторыми улучшениями (изменил часть кода и добавил автоопределение размера частей, которым в qbittorent и не пахнет:-\)
PSS. В связи с спецификой библиотеки libtorrent в windows наблюдаются проблемы с кириллицей в названиях файлов/каталогов. И если они присутствуют при создании torrent-файла, он может попросту быть пустым (ошибка кодировки). Потому для нормальной работы придется поиграться с кодировками. Что, к сожалению, у меня не вышло. В багрепорте библиотеки есть не одно сообщение с этой проблемой от русскоговорящих и от китайцев/корейцев, но разрабы видимо это попросту игнорируют. Потому просьба - если кто решит проблему с кодировками, поделитесь солюшеном.
Записан
niXman
Гость
« Ответ #1 : Март 02, 2010, 13:15 »

что-то вы намудрили.
"настройка boost" - все вами описанное можно выполнить опциями командной строки bjam.
"Настройка LIBTORRENT" - а смысл так усложнять все, только ради bjam? есть же стандартный скрипт configure
по поводу кодировок - у либторрент нет проблем с кодировками. если учесть, что разработчик либторрент не ориентируется на вендоюзеров, а так же то, что bencoded файлы !обязаны! содержать кодировку UTF, итог - все проблемы из-за венды.

ну и самое интересное:
тут: http://ru.wikipedia.org/wiki/Bencode описан формат bencode. из описания видно, что синтаксис простяцкий, и подсчет sha1 не проблема.
если забить в гугл слово bencode, то вы просто афанареете от кол-ва готовых реализаций.
на худой конец, можно просто выдрать из либторрент create_torrent.cpp и create_torrent.hpp, и поправить зависимости.
но лучше написать самому, для самообразования.
Записан
XpycT
Гость
« Ответ #2 : Март 02, 2010, 14:51 »

что-то вы намудрили.
"настройка boost" - все вами описанное можно выполнить опциями командной строки bjam.
"Настройка LIBTORRENT" - а смысл так усложнять все, только ради bjam? есть же стандартный скрипт configure
Возможно и намудрил (так как я почти не работаю с boost'ом, для меня это вполне приемлемый способ), но в большей степени настройка почти не отличается от приведенной в документации самого libtorrent. Просто я выложил более раскрыто. У меня все это занимает не более 2-5 минут.
по поводу кодировок - у либторрент нет проблем с кодировками. если учесть, что разработчик либторрент не ориентируется на вендоюзеров, а так же то, что bencoded файлы !обязаны! содержать кодировку UTF, итог - все проблемы из-за венды.
Я так и сказал - что в !windows! наблюдаются проблемы. Я прекрасно понимаю что .torrent файл чаще всего в UTF-8, а вот кодировка пути каталогов/файлов windows в основном используется форма UTF-16LE. Потому в PSS первого поста и упомянул, что придется играться кодировками. (в linux системах все прекрасно работает)
ну и самое интересное:
тут: http://ru.wikipedia.org/wiki/Bencode описан формат bencode. из описания видно, что синтаксис простяцкий, и подсчет sha1 не проблема.
если забить в гугл слово bencode, то вы просто афанареете от кол-ва готовых реализаций.
на худой конец, можно просто выдрать из либторрент create_torrent.cpp и create_torrent.hpp, и поправить зависимости.
но лучше написать самому, для самообразования.
Вот как раз в старом посте начало и было уделено самописному варианту, с форматом bencode проблем не возникло, но вот на подсчете суммы хешей и застрял, вроде как делал все по описанному в bencode формату, а полученый хеш так и не совпадал с "правильным" (созданным в torrent-клиентах ) Улыбающийся
Записан
niXman
Гость
« Ответ #3 : Март 02, 2010, 15:00 »

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

зы
прошлую тему я похоже невнимательно читал. или не до этого было. сейчас попробую проделать аналогичную задачу. должно работать. хз, посмотрим.
Записан
XpycT
Гость
« Ответ #4 : Март 02, 2010, 15:11 »

Если получится сделать стандартными методами Qt, буду признателен за помощь. Сам бы с удовольствием отказался от libtorrent, если  в винде пропадет проблема с разницей кодировок. Чисто принципиально не люблю таскать чужие либы в проектах Улыбающийся
Записан
niXman
Гость
« Ответ #5 : Март 02, 2010, 15:25 »

Цитировать
Чисто принципиально не люблю таскать чужие либы в проектах
никто не любит.

зы
сделаю на основе вашего проекта Улыбающийся
Записан
xintrea
Moderator
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #6 : Март 03, 2010, 02:34 »

По-моему, ваш HOWTO не соответсвует тематике раздела. У нас здесь уроки по Qt, а не по созданию частного решения для генерации torrent-файлов.

Пока думаю, переносить или нет.
Записан

Собираю информацию по крупицам
http://webhamster.ru
coder_gate
Гость
« Ответ #7 : Апрель 05, 2010, 10:46 »

i want build QT + Libtorrent + Mingw but when i do your instruction
error:


Цитировать
cd C:\Users\BotNetVN\Desktop\boost_1_42_0\tools\jam\src


bjam gcc release link=static boost= source


why ?
http://www.qtcentre.org/threads/29531-Build-Libtorrent-By-Mingw-windows-7


if you free, can  you upload your project ?, thanks
« Последнее редактирование: Апрель 05, 2010, 12:45 от coder_gate » Записан
coder_gate
Гость
« Ответ #8 : Апрель 05, 2010, 20:12 »

My source:

http://www.mediafire.com/?0mzlwz2ofgi


error:
Цитировать
release/main.o:main.cpp:(.text+0x138): undefined reference to `torrentCreatorThread::create(QString, QString, QStringList, QStringList, QString, bool, int)'
collect2: ld returned 1 exit status
mingw32-make[1]: *** [release\Make_Torrent.exe] Error 1
mingw32-make: *** [release] Error 2
Exited with code 2.
Error while building project Make_Torrent
Записан
xintrea
Moderator
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #9 : Апрель 06, 2010, 11:47 »

i want build QT + Libtorrent + Mingw but when i do your instruction
error:
why ?

http://www.qtcentre.org/threads/29531-Build-Libtorrent-By-Mingw-windows-7

if you free, can  you upload your project ?, thanks

На будущее: у нас тут русскоязычный форум.

По проблеме - начинать надо с правильной устновки boost. Пока не исчезнут ошибки вида unknown feature 'boost', далее компилировать смысла нет. Скорее всего boost у вас даже установлен, но где-то в проекте не прописаны пути к его заголовкам или библиотекам.

Подробнее вам объяснят любители винды, я, к сожалению, могу только по линуху что-то посоветовать.
Записан

Собираю информацию по крупицам
http://webhamster.ru
coder_gate
Гость
« Ответ #10 : Апрель 11, 2010, 10:17 »

createtorrent.cpp: In function 'bool file_filter(const std::string&)':
createtorrent.cpp:26: error: 'filename' was not declared in this scope
createtorrent.cpp: In member function 'virtual void torrentCreatorThread::run()':
createtorrent.cpp:226: error: 'complete' is not a member of 'libtorrent'
createtorrent.cpp:241: error: 'parent_path' was not declared in this scope
In file included from createtorrent.cpp:13:



Код:
bool file_filter(std::string const& f)
{
        if ([b][font=Verdana]filename(f)[0] [/font][/b]== '.') return false;
        //qDebug()<<f.c_str();
        return true;
}

Код:
void torrentCreatorThread::run() {
  emit updateProgress(0);
  char const* creator_str = "Torrent Uploader";
  try {

      file_storage fs;
      file_pool fp;
      std::string full_path = libtorrent::complete(input_path.toLocal8Bit().data());
      add_files(fs, full_path, file_filter);
      if(abort) return;
      create_torrent t(fs, piece_size);


Код:
set_piece_hashes(t, parent_path(full_path)
                       , boost::bind<void>(&sendProgressUpdateSignal, _1, t.num_pieces(), this));
Записан
coder_gate
Гость
« Ответ #11 : Апрель 11, 2010, 11:37 »

Код:
#include "createtorrent.h"
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include <QtCore/QDebug>
#include <QtCore/QTextCodec>

#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/create_torrent.hpp"
#include "libtorrent/file.hpp"

#include <boost/bind.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>

using namespace boost::filesystem;
using namespace libtorrent;

bool file_filter(boost::filesystem::path const& filename)
{
        if (filename.leaf()[0] == '.') return false;
        std::cerr << filename << std::endl;
        return true;
}



quint64 listFolder ( QString path ) {
        QDir currentFolder( path );

        quint64 totalsize = 0;

        currentFolder.setFilter( QDir::Dirs | QDir::Files | QDir::NoSymLinks );
        currentFolder.setSorting( QDir::Name );

        QFileInfoList folderitems( currentFolder.entryInfoList() );

        foreach ( QFileInfo i, folderitems ) {
                QString iname( i.fileName() );
                if ( iname == "." || iname == ".." || iname.isEmpty() )
                        continue;

                if ( i.isDir() )
                        totalsize += listFolder( path+"/"+iname );
                else
                        totalsize += i.size();
        }
        return totalsize;
}

createtorrent::createtorrent(QWidget *parent)
    :QDialog(parent)
{
    setupUi(this);
    setAttribute(Qt::WA_DeleteOnClose);
    setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint);
    layout()->setSizeConstraint(QLayout::SetFixedSize);

    creatorThread = new torrentCreatorThread(this);
    connect(creatorThread, SIGNAL(creationSuccess(QString)), this, SLOT(handleCreationSuccess(QString)));
    connect(creatorThread, SIGNAL(creationFailure(QString)), this, SLOT(handleCreationFailure(QString)));
    connect(creatorThread, SIGNAL(updateProgress(int)), this, SLOT(updateProgressBar(int)));
    path::default_name_check(no_check);
    show();
}
createtorrent::~createtorrent() {
  delete creatorThread;
}
void createtorrent::on_addFile_button_clicked()
{
    QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath(), QString(), 0, QFileDialog::ShowDirsOnly);
    if(!file.isEmpty())
      textInputPath->setText(file);
}

void createtorrent::on_addFolder_button_clicked()
{
    QString dir = QFileDialog::getExistingDirectory(this, tr("Select a folder to add to the torrent"), QDir::homePath(), QFileDialog::ShowDirsOnly);
    if(!dir.isEmpty())
      textInputPath->setText(dir);
}

int createtorrent::getPieceSize() const {
  switch(comboPieceSize->currentIndex()) {
  case 0:{
          QString file=textInputPath->text();
          QFileInfo fi(file);
          quint64 fileSize=0;
          quint64 dirSize=0;
          int pieceSize=0;
          int needToSet=0;

          if(fi.isFile()){
              fileSize=fi.size();
              pieceSize=fileSize/1000;
          }
          if(fi.isDir()){
              dirSize=listFolder(file);
              pieceSize=dirSize/1000;
          }
          if(pieceSize<(32*1024)){
              needToSet=32;
          }else if(pieceSize<(64*1024)){
              needToSet=64;
          }else if(pieceSize<(128*1024)){
              needToSet=128;
          }else if(pieceSize<(256*1024)){
              needToSet=256;
          }else if(pieceSize<(512*1024)){
              needToSet=512;
          }else if(pieceSize<(1024*1024)){
              needToSet=1024;
          }else if(pieceSize<(2048*1024)){
              needToSet=2048;
          }else{
              needToSet=4096;
          }
     return needToSet*1024;
  }
  case 1:
    return 32*1024;
  case 2:
    return 64*1024;
  case 3:
    return 128*1024;
  case 4:
    return 256*1024;
  case 5:
    return 512*1024;
  case 6:
    return 1024*1024;
  case 7:
    return 2048*1024;
  default:
    return 512*1024;
  }
}

QStringList createtorrent::allItems(QPlainTextEdit *list){
  QStringList res;
  QStringList tmp;

  tmp = list->toPlainText().split("\n");
  for(int i=0;i<tmp.length();i++){
      if(!QString(tmp.at(i)).simplified().isEmpty())
          res << QString(tmp.at(i)).simplified();
  }

  return res;
}

void createtorrent::on_createButton_clicked()
{
    QString input = textInputPath->text().trimmed();
    QString f=QFileInfo(input).fileName();
    qDebug()<<f;
    if (input.endsWith(QDir::separator()))
      input.chop(1);
    if(input.isEmpty()){
      QMessageBox::critical(0, tr("No input path set"), tr("Please type an input path first"));
      return;
    }
    QStringList trackers = allItems(trackers_list);
    QString destination = QFileDialog::getSaveFileName(this, tr("Select destination torrent file")
                                  , QDir::homePath()+QDir::separator()+f.replace(QRegExp(" "),".")+".torrent"
                                  , tr("Torrent Files")+QString::fromUtf8(" (*.torrent)"));
    if(!destination.isEmpty()) {
      if(!destination.endsWith(QString::fromUtf8(".torrent")))
        destination += QString::fromUtf8(".torrent");
    } else {
      return;
    }
    QStringList url_seeds = allItems(URLSeeds_list);
    QString comment = txt_comment->text();
    creatorThread->create(input, destination, trackers, url_seeds, comment, false, getPieceSize());

}

void createtorrent::handleCreationFailure(QString msg) {
  QMessageBox::information(0, tr("Torrent creation"), tr("Torrent creation was unsuccessful, reason: %1").arg(msg));
}

void createtorrent::handleCreationSuccess(QString path) {
  emit torrent_to_upload(path);
  QMessageBox::information(0, tr("Torrent creation"), tr("Torrent was created successfully:")+" "+path);
  close();
}
void createtorrent::updateProgressBar(int progress) {
  progressBar->setValue(progress);
}

//
// Torrent Creator Thread
//

void torrentCreatorThread::create(QString _input_path, QString _save_path, QStringList _trackers, QStringList _url_seeds, QString _comment, bool _is_private, int _piece_size) {
  input_path = _input_path;
  save_path = _save_path;
  trackers = _trackers;
  url_seeds = _url_seeds;
  comment = _comment;
  is_private = _is_private;
  piece_size = _piece_size;
  abort = false;
  start();
}

void sendProgressUpdateSignal(int i, int num, torrentCreatorThread *parent){
  parent->sendProgressSignal((int)(i*100./(float)num));
}

void torrentCreatorThread::sendProgressSignal(int progress) {
  emit updateProgress(progress);
}

void torrentCreatorThread::run() {
  emit updateProgress(0);
  char const* creator_str = "Torrent Uploader";
  try {

      file_storage fs;
      file_pool fp;
      path pfull_path = complete(input_path.toLocal8Bit().data());
      std::string full_path = pfull_path.root_name();
      add_files(fs, full_path, file_filter);
      if(abort) return;
      create_torrent t(fs, piece_size);
      QString seed;
      foreach(seed, url_seeds){
          t.add_url_seed(seed.toLocal8Bit().data());
      }
      for(int i=0; i<trackers.size(); ++i){
          t.add_tracker(trackers.at(i).toLocal8Bit().data());
      }
      if(abort) return;
      set_piece_hashes(t, pfull_path.parent_path()
                       , boost::bind<void>(&sendProgressUpdateSignal, _1, t.num_pieces(), this));
      if(abort) return;
      t.set_creator(creator_str);
      t.set_comment((const char*)comment.toLocal8Bit());
      t.set_priv(is_private);
      if(abort) return;

      ofstream out(complete(path((const char*)save_path.toLocal8Bit())), std::ios_base::binary);
      bencode(std::ostream_iterator<char>(out), t.generate());

      emit updateProgress(100);
      emit creationSuccess(save_path);
  }
  catch (std::exception& e){
//      qDebug() << e.what();
    emit creationFailure(QString::fromUtf8(e.what()));
  }
}
Записан
coder_gate
Гость
« Ответ #12 : Апрель 13, 2010, 13:58 »

i builded success project create torrent but people on internet when use my .torrent cant download it beacause it dont seeding,can you help me seeding 1 file when it create .torrent ?
source code: http://www.mediafire.com/?j0do4g11ajr
Записан
IlVolLeon
Гость
« Ответ #13 : Ноябрь 03, 2011, 07:18 »

Хоть и "в этой теме не было ответов в течение, по крайней мере 120 дней.", но:

Код:
char * ToUTF8(char * pszCode)
{
int nLength, nLength2;
BSTR bstrCode;
char *pszUTFCode = NULL;

nLength = MultiByteToWideChar(CP_ACP, 0, pszCode, lstrlen(pszCode), NULL, NULL);
bstrCode = SysAllocStringLen(NULL, nLength);
MultiByteToWideChar(CP_ACP, 0, pszCode, lstrlen(pszCode), bstrCode, nLength);


nLength2 = WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, pszUTFCode, 0, NULL, NULL);
pszUTFCode = (char*)malloc(nLength2+1);
WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, pszUTFCode, nLength2, NULL, NULL);

return pszUTFCode;
}

Аминь... Улыбающийся
« Последнее редактирование: Ноябрь 03, 2011, 07:24 от IlVolLeon » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.338 секунд. Запросов: 23.