Pull to refresh

Конвертация библиотеки lib.ru в epub формат средствами Java

Reading time4 min
Views3.6K
Доброго всем дня. Недавно у меня появился электронный ридер — Kobo Touch, и настал вопрос о том, откуда брать книги. Небезызвестная Флибуста конечно хорошая вещь и многие книгу я беру оттуда, но все-таки тянуло меня к lib.ru Да и ради интереса хотелось написать конвертер. Ненавистникам копро-кода стоит подумать о том. чтобы читать этот текст. Ибо код действительно неимоверно жестокий.

Проанализировав каталог библиотеки сразу стало ясно, что большинство книг имеют одну и туже схему, а именно:
[Автор].[Названия]
[Тех данные]
[#Глава]
[Текст главы]
[#Глава]
[Текст главы]
Ну и так далее. Повстречал я и другие формы, но не стал усложнять. Стоит отметить, что [Автор][Название] и[#Глава] находятся между определенными тэгами — "" и ""( это разные знаки, формат Ascii ).

Дело осталось за малым, написать простой парсер для страницы. Я воспользовался Java. Для начала встал вопрос, в какой кодировке считывать данные, ибо по моим наблюдениям — на каждой странице кодировка варируется. Для этого прибег к сторонней библиотеке juniversalchardet Так я узнаю кодировку и записываю его в строку.
 URLConnection con = url.openConnection();
            con.connect();
            InputStream urlfs;
            urlfs = con.getInputStream();
            byte[] buf = new byte[4096];
            UniversalDetector detector = new UniversalDetector(null);
            int nread;
            while ((nread = urlfs.read(buf)) > 0 && !detector.isDone()) {
            detector.handleData(buf, 0, nread);
            }
            detector.dataEnd();
            String encoding = detector.getDetectedCharset(); 
            detector.reset();

Далее читаю страницу с помощью BufferedReader.
  BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), encoding));
            String str;
            while ((str = in.readLine()) != null) {
                  string = string + str;
            }
            in.close();

Для удобного парсингазаменяю знак на и добавлю новый знак в конец файла.
        string = string.replace("", "");
         /* Т.к в конце страницы нету  знаков, то я их доабавляю для легкого парсинга. */
         string = string + " ";

В конце концов предстоит узнать сколько же всего глав в книге (как уже упомянуто, главы находятся между тэгами и ). Отнимаю также одну главу, ибо я сам добавил её.
  int count = 0;
         for (char c : string.toCharArray()) 
             if (c == '')
                 count++;    
         loop = (count-1);

Дело подходит к концу. Осталось разделить весь контент на главы, описания и автора с названием.
 /* Третья ячейка масива содержит строку вида "Автор. Название". Разделяю её. */
            String[] authorandtitle = parsedstring[2].split("\\.");   
            AUTHOR = authorandtitle[0];
            TITLE = authorandtitle[1];
             /* Начинаю добавлять главы, т.к они на четном месте массива. И текст на нечетных. Вырвиглазно, согласен */
            for(int i = 4; i <= loop; i++){
                if((i % 2) ==0 ){
                        CHAPTER[i] = parsedstring[i];
                        HEADER[i] = parsedstring[i];
                }else{
                        PARAG[i] = parsedstring[i];
                }
            }

Конечно можно было вытащить всё это регулярками, но что первое пришло в голову, то и написал.
Теперь имя всё для создания документа я воспользовался библиотекой EPUBGen для создания конечного документа. Благо примеры весьма информативные и это заняло буквально пару минут. Для начала создаю документ и вписываю метаданные.
      Publication epub = new Publication();
      epub.addDCMetadata("title", TITLE);
      epub.addDCMetadata("creator", AUTHOR);
      epub.addDCMetadata("language", "ru-RU");

Далее необходимо сохранить изображение в каталог OPS/images и сделать на него линк в документе cover.xhtml
  DataSource dataSource = new FileDataSource(new File(cover));
      BitmapImageResource imageResource = epub.createBitmapImageResource(
          "OPS/images/cover.jpg", "image/jpeg", dataSource);
      DataSource coverdata = new StringDataSource("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title>Cover</title>\n<style type=\"text/css\"> img { max-width: 100%; } </style>\n</head>\n<body>\n<div id=\"cover-image\">\n<img src=\"images/cover.jpg\" alt=\"Title\"/>\n</div>\n</body>\n</html>");
      Resource coverres = epub.createResource("OPS/cover.xhtml", "xhtml", coverdata);
      epub.addToSpine(coverres);

Последнее действие это добавление таблицы контента с последующим рекурсивным добавлением самого контента.
NCXResource toc = epub.getTOC();                                                       
TOCEntry rootTOCEntry = toc.getRootTOCEntry();

for(int i = 4; i <= loop; i++){
                if((i % 2) ==0 ){
      /* Создаю главу.*/
      OPSResource main = epub.createOPSResource("OPS/"+i+".html");
      epub.addToSpine(main);
      /* Открываю файл глав. */
      mainDoc = main.getDocument();
      /* Добавляю главу в таблицу контента.*/
      TOCEntry mainTOCEntry = toc.createTOCEntry(CHAPTER[i], mainDoc
          .getRootXRef());
      rootTOCEntry.add(mainTOCEntry);
     body = mainDoc.getBody();
      /* Добавляю тайтл. */
      Element h1 = mainDoc.createElement("h1");
      h1.add(HEADER[i]);
      body.add(h1);
        }else{
     /* Добавляю основной текст. */
      Element paragraph = mainDoc.createElement("p");
      paragraph.add(PARAG[i]);
      body.add(paragraph);
}
}

Сохраняю конечный документ
   OCFContainerWriter writer = new OCFContainerWriter(
          new FileOutputStream(output));
      epub.serialize(writer);

Конечный результат вышел таковой:

Интерфейс на Swing, зато дешево и сердито.
Так как больших усилий для понимания всей библиотеки я не предпринимал, работает лишь с книгами старой модели (простая текстовая модель), таких, как эта.
Кто не умер после прочтения такого обилия говно-кода, прошу на bitbucket Бинарник можно взять отсюда
Tags:
Hubs:
Total votes 36: ↑29 and ↓7+22
Comments9

Articles