Качаем 16GB торрент через планшет с 4GB свободного места

Качаем 16GB торрент через планшет с 4GB свободного места

Задача:

Есть ПК без интернета но есть возможность перекинуть файл по USB. Есть планшет с интернетом с которого этот файл можно перекинуть. На планшет можно скачать нужный торрент но не достаточно свободного места. Файл в торренте один и большой.

Путь к решению:

Я запустил торрент на загрузку. Когда свободное место почти подошло к концу я поставил загрузку на паузу. Подключил планшет к ПК и переместил файл с планшета на ПК. Отжал паузу и к моему удивлению файл был снова создан и торрент продолжил качаться дальше как ни в чем не бывало.

Благодаря тому что торрент клиент устанавливает sparse флаг файлу в который записывает полученные данные система не пытается зарезервировать сразу 16GB и не возникнет ошибки при попытке записи в файл дальше 4GB.

Повторив процедуру четыре раза я получил на ПК четыре файла в котором разные части одного и того же торрента. Теперь осталось собрать их воедино. Процедура по сути простая. Нужно заменить нуль байты на другое значение если оно есть в данной позиции в одном из четырёх файлов.

Мне казалось что такая простая программка должна быть в интернете. Неужели никто не сталкивался с такой задачей? Но я понял что даже не знаю по каким ключевым словам её искать. Поэтому я быстро накидал Lua скрипт под эту задачу а теперь уже и оптимизировал его. Им и хочу поделиться.

Загружаем торрент по частям

  1. запускаем загрузку торрента на первом устройстве
  2. ждём пока заполнится ПЗУ
  3. ставим загрузку на паузу
  4. переносим файл на второе устройство и добавляем к имени файла цифру
  5. возвращаемся к первому пункту до тех пор пока файл не скачается полностью

Сливаем части в один файл

После того как получена последняя часть необходимо собрать их в один целый файл.

Задача простая:

  1. Читаем все части одновременно
  2. Если в какой то части в позиции не нулевой байт то пишем на выход его иначе пишем ноль

Функция merge_part принимает массив потоков streams_in из которых читает часть размером buffer_length и возвращает результат слияния частей из разных потоков.

function merge_part(streams_in, buffer_length)
    local out_part
    for _, stream in ipairs(streams_in) do
        local in_part = stream:read(buffer_length)

        if not out_part then
            out_part = in_part -- просто копируем часть из первого файла
        elseif in_part and #in_part > 0 then

            if #out_part < #in_part then
                out_part, in_part = in_part, out_part
            end

            if out_part ~= in_part  -- данные различаются
                and in_part:find("[^ ]")   -- есть данные в in_part
                and out_part:find(" ", 1, true) -- есть пустые места в out_part
            then 
                local find_index = 1
--[[

Функция string.gsub подходит для задачи так как найдёт кусочки заполненные нулями и поставит то что передано ей.

--]]
                out_part = out_part:gsub(" +", function(zero_string)

                    if #in_part < find_index then
                        return -- не на что менять
                    end
--[[

string.gsub не передаёт позицию в которой был найдено совпадение. Поэтому делаем параллельный поиск позиции zero_string при помощи функции string.find. Достаточно найти первый нулевой байт.

--]]
                    local start_index = out_part:find(" ", find_index, true)
                    find_index = start_index + #zero_string

--[[

Теперь если в in_part есть данные для out_part копируем их.

--]]
                    if #in_part >= start_index then
                        local end_index = start_index + #zero_string - 1
--[[

Вырезаем из in_part часть соответствующую последовательности нулей.

--]]
                        local part = in_part:sub(start_index, end_index)

                        if (part:byte(1) ~= 0) or part:find("[^ ]") then
--[[

В part есть данные.

--]]
                            if #part == #zero_string then
                                return part
                            else
--[[

part оказался меньше чем последовательность нулей. Дополняем его ими.

--]]
                                return part..zero_string:sub(1, end_index - #in_part)
                            end
                        end
                    end
                end)
            end
        end
    end
    return out_part
end

Заключение

Таким образом удалось скачать и собрать этот файл на ПК. После слияния я вытащил с планшета торрент файл. Установил на ПК торрент клиент и проверил им файл.

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

Использовались:

  1. Торрент клиент Flud на планшете.
  2. Торрент клиент qBittorent на ПК.
  3. Lua скрипт

Источник: habr.com