/* * Copyright (C) 2005-2021 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #pragma once #include "guilib/GUIColorManager.h" #include "utils/ColorUtils.h" #include "utils/RegExp.h" #include #include #include #include #include #include #include #include enum class WebvttSection { UNDEFINED = 0, STYLE, STYLE_CONTENT, REGION, CUE, CUE_TEXT, CUE_METADATA, NOTE }; enum class WebvttAlign { AUTO = 0, LEFT, CENTER, RIGHT, START, END }; enum class WebvttVAlign { HORIZONTAL = 0, VERTICAL_RL, VERTICAL_LR, }; enum class TextAlignment { TOP_LEFT = 0, TOP_CENTER, TOP_RIGHT, SUB_LEFT, SUB_CENTER, SUB_RIGHT }; struct webvttAutoValue { double value = 0; bool isAuto = true; }; struct webvttCueSettings { std::string id; std::string regionId; WebvttVAlign verticalAlign; bool snapToLines; webvttAutoValue line; webvttAutoValue position; WebvttAlign positionAlign; double size; WebvttAlign align; bool operator==(webvttCueSettings const& other) const { return this->verticalAlign == other.verticalAlign && this->snapToLines == other.snapToLines && this->line.isAuto == other.line.isAuto && this->line.value == other.line.value && this->position.isAuto == other.position.isAuto && this->position.value == other.position.value && this->positionAlign == other.positionAlign && this->size == other.size && this->align == other.align; } }; struct subtitleData { std::string text; std::string textRaw; // Text without tags webvttCueSettings cueSettings; double startTime; double stopTime; bool useMargins; int marginLeft; int marginRight; int marginVertical; TextAlignment textAlign; }; enum class WebvttSelector { ANY = 0, ID, TYPE, CLASS, ATTRIBUTE, UNSUPPORTED }; struct webvttCssStyle { webvttCssStyle() {} webvttCssStyle(WebvttSelector selectorType, const std::string& selectorName, const std::string& colorHexRGB) : m_selectorType{selectorType}, m_selectorName{selectorName} { // Color hex values need to be in BGR format m_color = colorHexRGB.substr(4, 2) + colorHexRGB.substr(2, 2) + colorHexRGB.substr(0, 2); } WebvttSelector m_selectorType = WebvttSelector::ANY; std::string m_selectorName; std::string m_color; bool m_isFontBold = false; bool m_isFontItalic = false; bool m_isFontUnderline = false; }; struct tagToken { std::string m_token; // Entire tag std::string m_tag; std::string m_timestampTag; std::string m_annotation; std::vector m_classes; bool m_isClosing; }; class CWebVTTHandler { public: CWebVTTHandler(){}; ~CWebVTTHandler(){}; /*! * \brief Prepare the handler to the decoding */ bool Initialize(); /* * \brief Reset handler data */ void Reset(); /*! * \brief Verify the validity of the WebVTT signature */ bool CheckSignature(const std::string& data); /*! * \brief Decode a line of the WebVTT text data * \param line The line to decode * \param subList The list to be filled with decoded subtitles */ void DecodeLine(std::string line, std::vector* subList); /* * \brief Return true if the margins are handled by the parser. */ bool IsForcedMargins() const { return !m_overridePositions; } /* * \brief Set the period start pts to sync subtitles */ void SetPeriodStart(double pts) { m_offset = pts; } protected: void CalculateTextPosition(std::string& subtitleText); void ConvertSubtitle(std::string& text); void GetCueSettings(std::string& cueSettings); subtitleData m_subtitleData; private: bool IsCueLine(std::string& line); void GetCueData(std::string& cueText); std::string GetCueSettingValue(const std::string& propName, std::string& text, std::string defaultValue); std::string GetCueCssValue(const std::string& cssPropName, std::string& line); void AddDefaultCssClasses(); void InsertCssStyleStartTag(const tagToken& tag, std::string& text, int& pos, int flagTags[], std::deque>& cssTagsOpened); void InsertCssStyleCloseTag(const tagToken& tag, std::string& text, int& pos, int flagTags[], std::deque>& cssTagsOpened, webvttCssStyle& baseStyle); bool GetBaseStyle(webvttCssStyle& style); void ConvertAddSubtitle(std::vector* subList); void LoadColors(); double GetTimeFromRegexTS(CRegExp& regex, int indexStart = 1); // Last subtitle data added, must persist and be updated between all demuxer packages std::unique_ptr m_lastSubtitleData; std::string m_previousLines[3]; bool m_overrideStyle{false}; bool m_overridePositions{false}; WebvttSection m_currentSection{WebvttSection::UNDEFINED}; CRegExp m_cueTimeRegex; CRegExp m_timeRegex; std::map m_cuePropsMapRegex; CGUIColorManager m_colorManager; CRegExp m_tagsRegex; CRegExp m_cueCssTagRegex; std::map m_cueCssStyleMapRegex; std::vector m_feedCssSelectorNames; webvttCssStyle m_feedCssStyle; std::map> m_cssSelectors; bool m_CSSColorsLoaded{false}; std::vector> m_CSSColors; double m_offset{0.0}; };