Извлечь максимум из новостей в интернете, часть 3

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Часть 3

Как я автоматизировал доставку аудиоподкастов на свой плеер

Продолжение статьи про новости - как я скачиваю подкасты. Предыдущие части тут и тут.

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

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

Я прошёл долгий путь по выбору конкретного аудиопроигрывателя (и, возможно, этот путь ещё не закончен) - bluetooth-наушники в связке со смартфоном, наушники со встроенным плеером, и прочее и прочее. Сейчас у меня есть простенький китайский mp3-плеер (которых было заказано сразу несколько штук и в случае поломок можно просто выкинуть один и взять другой). Цена вопроса - около 300 рублей за штуку. Если плеер проработает хотя бы 1 год, то это просто удача. В моём случае один плеер работает уже с декабря 2019, что я считаю, признак успеха китайской промышленности.

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

Мне очень « зашли » подкасты радио Маяк. В школе я не любил историю - все эти сухие даты, непонятные события (когда алая Роза напала на Белую Розу или наоборот? и чем вообще эта буза закончилась?). Но сейчас мне эта тема почему-то стала интересна, особенно если тему раскрывает интересный рассказчик. История страны, история мира. Интересны подкасты про общее развитие, про новые технологии. Аудио-книги, которые в своё время не успел прочитать. Всё очень интересно. И очень удобно.

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

Задача: Хочется скачивать аудиофайлы с сайта радио Маяк, и раскладывать их по каталогам, чтобы потом в дальнейшем легко копировать на плеер.

Для начала посмотрим, что же пишется в файле новостей из радио Маяк. Возьмём для примера подкаст «30 сюжетов цивилизации»:

Как видим, у каждой новости (одна новость = одна радио-передача = rss.channel.item) есть тэг enclosure с гиперссылкой (атрибут url) на mp3-файл. Это именно то, что нам нужно.

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

Не помешает база данных. Что бы использовать? Я для себя выбрал 1С - там встроенная база данных (как в MS Access), есть работа с интернетом (загрузка файлов), парсинг xml, работа с файловой системой, можно буквально мышкой нарисовать интерфейс - и всё это "из коробки"! Плюс у меня есть некоторый опыт работы с 1С.

У 1С есть бесплатный вариант (версия «для обучения  программированию»), которую можно бесплатно и без смс скачать с сайта (http://online.1c.ru/catalog/programs/program/28765768/) - это свежая версия на текущий момент. Для загрузки потребуется только емейл.

У версии «для обучения программированию» есть ограничения по количеству записей в таблицах. Но это не проблема - вместо одной большой базы данных можно создать несколько маленьких.

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

Итак, я скачал версию 1С «для обучения программированию»…

Опустим процесс инсталляции. Там всё просто.

Почти по аналогии с MS Access (где одна база = один файл), В 1С одна база = один каталог. При запуске 1С надо будет указать какой-то каталог в качестве каталога нужной базы данных. После этого можно нажать «Конфигуратор», чтобы открыть IDE для редактирования кода и интерфейса.

Информационная база 1С состоит, грубо говоря, из непосредственно данных и из метаданных. Метаданные - код на языке 1С, описание интерфейса и прочая информация.

Можно хранить данные и метаданные в системе баз данных (MS SQL, Postgres), но 1С умеет работать и с локальной базой данных (формат 1С). Локальная файловая база данных 1С - это один файл с фиксированным именем «1Cv8.1CD», который лежит в заданном каталоге. Версия для обучения позволяет работать только с файловой базой, прикрутить Postgres к ней не получится.

Таблицы баз данных (в терминологии систем баз данных) в 1С будут называться «Справочниками» (условно постоянная информация), «Документами» (информация об изменении данных), всякими «Регистрами сведений», «Регистрами накоплений», «Регистрами бухгалтерии» (непосредственно значения изменённых данных).

Для моих целей нужно будет создать:

  • справочник «Подкасты», где хранится список интересных мне подкастов с URL на всю RSS-ленту новостей этого подкаста;

  • справочник «Аудиоматериалы», где хранятся URL на конкретные файлы MP3;

  • регистр сведений «ГлобальныеНастройки», где хранятся прочие настройки, например корневой каталог в файловой системе, куда скачивать mp3-файлы.

Формы для ввода данных для этих справочников рисуются буквально мышкой.

Вот, например, настроенный внешний вид справочника «Подкасты» (ни строчки кода!):

Если форму не рисовать, то платформа 1С сама её создаст, «на лету». Собственно, форма ввода для справочника «Подкасты» - единственная, которую я делал сам, «ручками». Остальные формы ввода платформа 1С генерирует автоматически.

Например, формы «1» и «2» платформа 1С нарисовала сама:

Данные для подкастов пришлось вводить ручками, но это одноразовое действие:

Дальше пришлось немного написать кода на языке 1С. Я знаю, что многие на хабре не считают 1С нормальным языком. Но как по мне, 1С умеет делать всё, что умеют все остальные языки. И это всё «из коробки». Ребятки, сравните-ка код 1С по построчному чтению файла в старых версиях Java (статья на хабре: Эволюция Java на примере чтения строк из файла) и код 1С:

&НаКлиенте
Процедура КомандаПрочитатьФайл(Команда)

    ЧтениеТекста = Новый ЧтениеТекста("e:\Data\Texts\Статья на хабре, новости\Attachments\30 сюжетов цивилизации RSS.xml", "UTF-8");
    ТекущаяСтрока = ЧтениеТекста.ПрочитатьСтроку();
    Пока ТекущаяСтрока <> Неопределено Цикл
        // Обработать строку
        ТекущаяСтрока = ЧтениеТекста.ПрочитатьСтроку();
    КонецЦикла;

КонецПроцедуры

Но извините, я отвлёкся.

Кода на 1С будет не очень много:

КомандаЗагрузитьСписокАудиоматериалов - для выделенных строк. 1С подключается к RSS-ленте, загружает XML, парсит его, и добавляет новые файлы для загрузки в справочник «АудиоМатериалы». Одна новость = один файл.

Загрузка файла из интернет:

&НаСервере
Процедура ЗагрузитьСписокАудиоматериаловДляПодкаста(Подкаст, URL)

    // 1. Загрузить XML-файл со списком аудиоматериалов.
    РазложенныйURL = СтрРазделить(URL, "/", Ложь);
    Сервер       = РазложенныйURL[1]; // https://radiomayak.ru/podcasts/rss/podcast/3321/type/audio/ -> radiomayak.ru
    Порт         = Неопределено;
    Пользователь = Неопределено;
    Пароль       = Неопределено;
    Прокси       = Новый ИнтернетПрокси(Истина);
    Таймаут      = 30;

    HTTPСоединение = Новый HTTPСоединение(
        Сервер,
        Порт,
        Пользователь, 
        Пароль,
        Прокси,
        Таймаут,
        Новый ЗащищенноеСоединениеOpenSSL,
        Ложь);

    РазложенныйАдресРесурса = РазложенныйURL;
    РазложенныйАдресРесурса.Удалить(0); // http
    РазложенныйАдресРесурса.Удалить(0); // сервер
    АдресРесурса = СтрСоединить(РазложенныйАдресРесурса, "/");

    Заголовки = Новый Соответствие;
    HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
    HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод("GET", HTTPЗапрос);

    Если HTTPОтвет.КодСостояния = 200 Тогда
        ТелоОтвета = HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);

//// И так далее...

Парсинг загруженного XML и сохранение в справочник «АудиоМатериалы»:

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТелоОтвета);
    ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
    СписокАудиоМатериаловXDTO = ОбъектXDTO.channel.ПолучитьСписок("item");
    Для Каждого ТекущийЭлементXDTO Из СписокАудиоМатериаловXDTO Цикл
        Длительность    = ТекущийЭлементXDTO.duration;
        ДлительностьЧас = Число(Сред(Длительность, 1, 2));
        ДлительностьМин = Число(Сред(Длительность, 4, 2));
        ДлительностьСек = Число(Сред(Длительность, 7, 2));
        ДатаОбновления  = ДатаRFC1123(ТекущийЭлементXDTO.pubDate);
        Описание        = ?(ТекущийЭлементXDTO.Свойства().Получить("summary") = Неопределено, "", ТекущийЭлементXDTO.summary);
        Заголовок       = ТекущийЭлементXDTO.title;
        УИН             = ТекущийЭлементXDTO.guid.Последовательность().ПолучитьТекст(0);
        Гиперссылка     = ТекущийЭлементXDTO.enclosure.url;
        РазмерФайла     = ?(ТекущийЭлементXDTO.enclosure.Свойства().Получить("length") = Неопределено, 0, ТекущийЭлементXDTO.enclosure.length);
        // Найти элемент справочника АудиоМатериалы по УИН
        АудиоМатериалСсылка = Справочники.АудиоМатериалы.НайтиПоРеквизиту("УИН", УИН, , Подкаст);
        Если АудиоМатериалСсылка.Пустая() Тогда
            АудиоМатериалОбъект = Справочники.АудиоМатериалы.СоздатьЭлемент();
        Иначе
            АудиоМатериалОбъект = АудиоМатериалСсылка.ПолучитьОбъект();
        КонецЕсли;
            АудиоМатериалОбъект.Владелец           = Подкаст;
            АудиоМатериалОбъект.УИН                = УИН;
            АудиоМатериалОбъект.Наименование       = Заголовок;
            АудиоМатериалОбъект.URL                = Гиперссылка;
            АудиоМатериалОбъект.ДлительностьЧасов  = ДлительностьЧас;
            АудиоМатериалОбъект.ДлительностьМинут  = ДлительностьМин;
            АудиоМатериалОбъект.ДлительностьСекунд = ДлительностьСек;
            АудиоМатериалОбъект.Описание           = Описание;
            АудиоМатериалОбъект.РазмерФайла        = РазмерФайла;
            АудиоМатериалОбъект.ДатаОбновления     = ДатаОбновления;
        АудиоМатериалОбъект.Записать();
    КонецЦикла;
ЧтениеXML.Закрыть();

Не люблю формат RSS из-за формата даты RFC 1123 (если точнее, то RFC 822, часть 5) - <pubDate>Sun, 21 May 2017 11:00:00 GMT</pubDate>. Пришлось написать ещё немного кода:

&НаСервере
// Возвращает дату, преобразованную из формата RFC 1123 в тип Дата.
Функция ДатаRFC1123(ДатаСтрокойHTTP)

    ИменаМесяцев = "janfebmaraprmayjunjulaugsepoctnovdec";
    // rfc1123-date = wkday "," SP date1 SP time SP "GMT".
    ПозицияПервогоПробела = СтрНайти(ДатаСтрокойHTTP, " ");//с первого пробела до второго пробела идет дата.
    ПодстрокаДата = Сред(ДатаСтрокойHTTP,ПозицияПервогоПробела + 1);
    ПодстрокаВремя = Сред(ПодстрокаДата, 13);
    ПодстрокаДата = Лев(ПодстрокаДата, 11);
    ПозицияПервогоПробела = СтрНайти(ПодстрокаВремя, " ");
    ПодстрокаВремя = Лев(ПодстрокаВремя,ПозицияПервогоПробела - 1);
    // date1 = 2DIGIT SP month SP 4DIGIT.
    ПодстрокаДень = Лев(ПодстрокаДата, 2);
    ПодстрокаМесяц = Формат(Цел(СтрНайти(ИменаМесяцев,НРег(Сред(ПодстрокаДата,4,3))) / 3)+1, "ЧЦ=2; ЧН=00; ЧВН=");
    ПодстрокаГод = Сред(ПодстрокаДата, 8);
    // time = 2DIGIT ":" 2DIGIT ":" 2DIGIT.
    ПодстрокаЧас = Лев(ПодстрокаВремя, 2);
    ПодстрокаМинута = Сред(ПодстрокаВремя, 4, 2);
    ПодстрокаСекунда = Прав(ПодстрокаВремя, 2);

    Возврат Дата(ПодстрокаГод + ПодстрокаМесяц + ПодстрокаДень + ПодстрокаЧас + ПодстрокаМинута + ПодстрокаСекунда);

КонецФункции

После того, как мы сохранили в таблице список URL mp3-файлов, можно их загрузить. Если запустить 1С в режиме "Предприятие", то в справочнике «Подкасты» можно выделить несколько строк и нажать «Загрузить аудиоматериалы».

КомандаЗагрузитьАудиоматериалы - анализирует данные из справочника «АудиоМатериалы» и сравнивает с уже загруженными файлами в файловой системе. Если файла нет или размер не совпадает, то он будет загружен.

Данные в можно получать запросами, очень похожими на обычный SQL:

Запрос = Новый Запрос;
Запрос.Текст = "
    |ВЫБРАТЬ
    |    ЛОЖЬ                                          КАК Загружать,
    |    Спр.Владелец.Наименование                     КАК Подкаст,
    |    &КаталогМедиаФайлов                           КАК КаталогМедиаФайлов,
    |    Спр.Владелец.КаталогСохраненияАудиоматериалов КАК КаталогСохраненияАудиоматериалов,
    |    Спр.Владелец.ШаблонИмениФайла                 КАК ШаблонИмениФайла,
    |    &Строка255                                    КАК ИмяФайла,
    |    Спр.Наименование                              КАК Наименование,
    |    Спр.URL                                       КАК URL,
    |    Спр.Описание                                  КАК Описание,
    |    Спр.ДатаОбновления                            КАК ДатаОбновления,
    |    ""          ""                                КАК ДатаОбновленияГГГГММДД,
    |    Спр.ДлительностьЧасов                         КАК ДлительностьЧасов,
    |    Спр.ДлительностьМинут                         КАК ДлительностьМинут,
    |    Спр.ДлительностьСекунд                        КАК ДлительностьСекунд,
    |    ""     ""                                     КАК ДлительностьММСС,
    |    Спр.РазмерФайла                               КАК РазмерФайлаНадо,
    |    0                                             КАК РазмерФайлаЕсть
    |ИЗ
    |    Справочник.АудиоМатериалы КАК Спр
    |ГДЕ
    |    Спр.Владелец В (&Подкасты)
    |    И Спр.Владелец.ПометкаУдаления = ЛОЖЬ
    |УПОРЯДОЧИТЬ ПО
    |    Спр.Владелец.Наименование
    |";
Запрос.УстановитьПараметр("Подкасты"          , МассивПодкастов);
Запрос.УстановитьПараметр("Строка255"         , Строка255);
Запрос.УстановитьПараметр("КаталогМедиаФайлов", КаталогМедиаФайлов);

РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
    // Обработка данных запроса
КонецЕсли;

Хэдхантеры, вы вообще в курсе, что даже начинающий «1С-ник из коробки» уже умеет SQL?

Проверяем, наличие файлов. Если файл есть и его размер совпадает, то загружать заново смысла нет. Если файла нет или его размер не совпадает - загрузим снова.

// Подготовить имена файлов
ТаблицаФайлов = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.Прямой);
Для Каждого ТекущийФайл Из ТаблицаФайлов Цикл
    Если СтрЗаканчиваетсяНа(ТекущийФайл.КаталогМедиаФайлов, "\") Тогда
        ТекущийФайл.КаталогМедиаФайлов = Лев(ТекущийФайл.КаталогМедиаФайлов, СтрДлина(ТекущийФайл.КаталогМедиаФайлов) - 1);
    КонецЕсли;
    Если СтрЗаканчиваетсяНа(ТекущийФайл.КаталогСохраненияАудиоматериалов, "\") Тогда
        ТекущийФайл.КаталогСохраненияАудиоматериалов = Лев(ТекущийФайл.КаталогСохраненияАудиоматериалов, СтрДлина(ТекущийФайл.КаталогСохраненияАудиоматериалов) - 1);
    КонецЕсли;
    ТекущийФайл.ДатаОбновленияГГГГММДД = Формат(ТекущийФайл.ДатаОбновления, "ДФ=yyyy-MM-dd");
    ТекущийФайл.ДлительностьММСС = Формат(ТекущийФайл.ДлительностьМинут, "ЧЦ=2; ЧН=00; ЧВН=") + "." + Формат(ТекущийФайл.ДлительностьСекунд, "ЧЦ=2; ЧН=00; ЧВН=");
    ТекущийФайл.КаталогСохраненияАудиоматериалов = ЗаменитьПеременные(ТекущийФайл.КаталогСохраненияАудиоматериалов, ТекущийФайл, ПравилаЗамены);
    ТекущийФайл.ИмяФайла = ЗаменитьПеременные(ТекущийФайл.ШаблонИмениФайла, ТекущийФайл, ПравилаЗамены);
    ТекущийФайл.ИмяФайла = УдалитьЗапрещенныеСимволы(ТекущийФайл.ИмяФайла);
КонецЦикла;

// Проверить файлы на наличие и размер.
// Параллельно проверить и сформировать структуру каталогов.
Для Каждого ТекущийФайл Из ТаблицаФайлов Цикл
    Файл = Новый Файл(ТекущийФайл.КаталогСохраненияАудиоматериалов + "\" + ТекущийФайл.ИмяФайла);
    Если Файл.Существует() Тогда
        ТекущийФайл.РазмерФайлаЕсть = Файл.Размер();
        Если ТекущийФайл.РазмерФайлаЕсть <> ТекущийФайл.РазмерФайлаНадо Тогда
            ТекущийФайл.Загружать = Истина;
        КонецЕсли;
    Иначе
        СтруктураКаталогов = СтрРазделить(ТекущийФайл.КаталогСохраненияАудиоматериалов + "\" + ТекущийФайл.ИмяФайла, "\", Ложь);
        ТекущееИмяКаталога = СтруктураКаталогов[0];
        Для С=1 По СтруктураКаталогов.ВГраница()-1 Цикл // Без имени диска и без самого имени файла.
            ТекущееИмяКаталога = ТекущееИмяКаталога + "\" + СтруктураКаталогов[С];
            ТекущийКаталог = Новый Файл(ТекущееИмяКаталога);
            Если НЕ ТекущийКаталог.Существует() Тогда
                СоздатьКаталог(ТекущееИмяКаталога);
            КонецЕсли;
        КонецЦикла;
        ТекущийФайл.Загружать = Истина;
    КонецЕсли;
КонецЦикла;
// Загрузить несуществующие файлы.
Для Каждого ТекущийФайл Из ТаблицаФайлов Цикл
    Если ТекущийФайл.Загружать = Истина Тогда
        ЗагрузитьФайл(ТекущийФайл.URL, ТекущийФайл.КаталогСохраненияАудиоматериалов + "\" + ТекущийФайл.ИмяФайла);
        ОбновитьОписаниеФайла(ТекущийФайл.ИмяФайла, ТекущийФайл.КаталогСохраненияАудиоматериалов, ТекущийФайл.Описание);
    КонецЕсли;
КонецЦикла;

Непосредственно загрузка:

&НаСервере
Процедура ЗагрузитьФайл(URL, ПолноеИмяФайла)

    РазложенныйURL = СтрРазделить(URL, "/", Ложь);
    Сервер       = РазложенныйURL[1]; // https://radiomayak.ru/podcasts/rss/podcast/3321/type/audio/ -> radiomayak.ru
    Порт         = Неопределено;
    Пользователь = Неопределено;
    Пароль       = Неопределено;
    Прокси       = Новый ИнтернетПрокси(Истина);
    Таймаут      = 30;

    HTTPСоединение = Новый HTTPСоединение(
        Сервер,
        Порт,
        Пользователь,
        Пароль,
        Прокси,
        Таймаут,
        Новый ЗащищенноеСоединениеOpenSSL,
        Ложь);

    РазложенныйАдресРесурса = РазложенныйURL;
    РазложенныйАдресРесурса.Удалить(0); // http
    РазложенныйАдресРесурса.Удалить(0); // сервер
    АдресРесурса = СтрСоединить(РазложенныйАдресРесурса, "/");

    Заголовки = Новый Соответствие;
    HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
    HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод("GET", HTTPЗапрос);

    Если HTTPОтвет.КодСостояния = 200 Тогда
        ДвоичныеДанныеФайла = HTTPОтвет.ПолучитьТелоКакДвоичныеДанные();
        ДвоичныеДанныеФайла.Записать(ПолноеИмяФайла);
    Иначе
        Сообщить(
            СтрШаблон(
                НСтр("ru='Ошибка загрузки: код %1, сервер %2, ресурс %3'"),
                HTTPОтвет.КодСостояния,
                Сервер,
                АдресРесурса));
    КонецЕсли;

КонецПроцедуры

В качестве файлового менеджера я использую «Total commander». Купил его официально, но в принципе программа работает и бесплатно - всего-навсего при запуске программы надо будет нажать одну из трёх случайных кнопок.

В «Total commander» в каталоге можно сохранить файл «descript.ion», в котором можно хранить комментарии к файлам. Это очень удобно. Эти комментарии в отдельном файле (в отличие от потоков в NTFS) сохраняются при копировании на FAT (естественно, если копировать с помощью "Total Commander"). Некоторые умельцы даже умеют показывать такие комментарии и в стандартном проводнике Windows (https://dudom.ru/kompjutery/kak-dobavit-kommentarij-k-fajlu/), но я не пробовал.

Например, в комментарии можно хранить некие тэги, например «Просмотрено;» и настроить сам «Total commander», чтобы файлы помеченные таким тэгом показывались серым цветом (скриншот будет ниже). Удобно.

Структура файла «descript.ion» очень простая: имя файла (возможно, в кавычках) и через пробел - произвольный комментарий:

Поэтому, при загрузке файла, можно сразу делать запись в этот «descript.ion»:

&НаСервере
Процедура ОбновитьОписаниеФайла(ИмяФайла, КаталогСохраненияАудиоматериалов, Описание)

    // Найти / создать в КаталогСохраненияАудиоматериалов файл descript.ion
    ИмяФайлаОписания = КаталогСохраненияАудиоматериалов + "\descript.ion";
    ФайлОписаний = Новый Файл(ИмяФайлаОписания);
    Если ФайлОписаний.Существует() Тогда
        ЧтениеТекста = Новый ЧтениеТекста(ИмяФайлаОписания, КодировкаТекста.ANSI, Символы.ПС, Символы.ПС, Ложь);
        ВсеСодержимое = ЧтениеТекста.Прочитать();
        ЧтениеТекста.Закрыть();
    Иначе
        ВсеСодержимое = "";
    КонецЕсли;

    // Найти / добавить в файле КаталогСохраненияАудиоматериалов\descript.ion строку, начинающуюся с ИмяФайла и содержащую Описание (замена переводов строк на \n)
    ВсеНовыеСтроки = Новый Массив;
    ОписаниеБезПереводовСтрок = Описание;
    ОписаниеБезПереводовСтрок = СтрЗаменить(ОписаниеБезПереводовСтрок, "<br>", "\n");
    ОписаниеБезПереводовСтрок = СтрЗаменить(ОписаниеБезПереводовСтрок, "<br/>", "\n");
    ОписаниеБезПереводовСтрок = СтрЗаменить(ОписаниеБезПереводовСтрок, Символы.ПС, "\n");
    ОписаниеБезПереводовСтрок = СтрЗаменить(ОписаниеБезПереводовСтрок, Символы.ВК, "\n");
    ОписаниеБезПереводовСтрок = СтрЗаменить(ОписаниеБезПереводовСтрок, "\n\n", "\n");
    Если НЕ ПустаяСтрока(ВсеСодержимое) Тогда
        НайденТекущийФайл = Ложь;
        ВсеСтарыеСтроки = СтрРазделить(ВсеСодержимое, Символы.ПС, Ложь);
        Для Каждого ТекущаяСтрока Из ВсеСтарыеСтроки Цикл
            Если СтрНачинаетсяС(ТекущаяСтрока, """" + ИмяФайла + """" + " ") Тогда
                ВсеНовыеСтроки.Добавить("""" + ИмяФайла + """" + " " + ОписаниеБезПереводовСтрок);
                НайденТекущийФайл = Истина;
            Иначе
                ВсеНовыеСтроки.Добавить(ТекущаяСтрока);
            КонецЕсли;
        КонецЦикла;
        Если НайденТекущийФайл <> Истина Тогда
            ВсеНовыеСтроки.Добавить("""" + ИмяФайла + """" + " " + ОписаниеБезПереводовСтрок);
        КонецЕсли;
    Иначе
        ВсеНовыеСтроки.Добавить("""" + ИмяФайла + """" + " " + ОписаниеБезПереводовСтрок);
    КонецЕсли;

    // Записать в файл обратно.
    Если ВсеНовыеСтроки.Количество() > 0 Тогда
        ЗаписьТекста = Новый ЗаписьТекста(ИмяФайлаОписания, КодировкаТекста.ANSI, Символы.ПС, Ложь, Символы.ПС);
        ЗаписьТекста.Записать(СтрСоединить(ВсеНовыеСтроки, Символы.ПС));
        ЗаписьТекста.Закрыть();
    КонецЕсли;

КонецПроцедуры

А вот и скачанные файлы, которые можно просто скопировать на плеер:

Обратите внимание, что если в комментарии к файлу есть «Просмотрено;», то он показывается серым цветом шрифта. «Total commander» умеет выделять файлы цветом по разным условиям (атрибуты файла, размер, наличие текста в комментарии, плагины), что очень удобно. По логике, конечно же, надо было бы назвать тэг «Прослушано;», а не «Просмотрено», но это просто устоявшийся у меня порядок, менять который - лениво. Извините.

Если кому интересно - можно выложить эту базу 1С в общий доступ, но к сожалению на хабре нельзя приаттачивать файлы к статье (или я не разобрался?).

Размер только метаданных (1cv8.cf) - 18 051 байт.

Размер выгруженной и сжатой базы (данные + метаданные, 1cv8.dt) - 662 650 байт.

Размер базы на диске (1Cv8.1CD) - 9 601 024 байт.

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

Какая была цель у этих статей? Продвинуть какую-то технологию или программу? Реклама? Поделиться опытом? Пусть это будет «поделиться опытом».

И в завершение:

  • Не стесняйтесь экспериментировать;

  • Изменяйте мир в лучшую сторону;

  • И не забывайте делиться своим опытом, чтобы другие тоже могли изменять мир в лучшую сторону.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Приаттачить базу 1С

  • 100,0%База 1С? Серьёзно? Это никому не интересно1
  • 0,0%ГитХаб0
  • 0,0%Облако мейл.ру0
  • 0,0%Яндекс.диск0
  • 0,0%Гугл драйв0
  • 0,0%Другое (напишу в комментарии)0
Источник: https://habr.com/ru/post/551836/


Интересные статьи

Интересные статьи

Привет, Хабровчане! В конце августа в OTUS запускается 2 мощных курса по обратной разработке кода (реверс-инжиниринг). В связи с этим приглашаем вас на День Открытых дверей, где Арту...
«Дураки учатся на своих ошибках, а умные — на чужих» Теодор Рузвельт, 26-й президент США Теодор Рузвельт, к сожалению, не был знаком с подходом MVP, и в соответствии с этим высказ...
В данной статье мы разберемся с эксплуатацией некоторых WEB-узвимостей на примере прохождения варгейма Natas. Каждый уровень имеет доступ к паролю следующего уровня. Все пароли также хранятся...
В предыдущих частях туторов мы рассматривали то, как создаются текстуры. Точнее, то, как всё выглядит под капотом (как выразился Yoooriii в комментариях к 4-ой части). Расставили на свои места те...
В прошлом посте я начал рассказ про Школу 42, которая славится своей революционной системой обучения: там нет учителей, студенты сами проверяют друг у друга работы, платить за учебу не нужно. В...