├── .clang-format ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CPPLINT.cfg ├── LICENSE ├── README.md ├── build ├── .gitignore ├── brands │ └── fastotv │ │ └── fastotv.txt ├── build.py ├── build_env.py ├── build_server_remote.py ├── devices │ ├── __init__.py │ ├── orange_pi │ │ ├── __init__.py │ │ ├── hardware │ │ │ └── lirc │ │ │ │ └── hardware.conf │ │ └── orange_pi.py │ └── raspberry_pi │ │ ├── __init__.py │ │ └── raspberry_pi.py └── patch │ └── orange-pi │ └── sdl2 │ └── SDL_render_gles2.c.patch ├── docs └── Doxyfile.in ├── images ├── 1024 px_horizontal-01.png ├── 128 px-01.png ├── 144 px-01.png ├── 256 px-01.png ├── 256 px_horizontal-01.png ├── 48 px-01.png ├── 480 px-01.png ├── 480_2 px-01.png ├── 512 px-01.png ├── 512 px_horizontal-01.png ├── 72 px-01.png ├── Horizontal Black-01.png ├── Horizontal White-01.png ├── Logo Black-01.png ├── Logo White-01.png ├── Logo license.txt ├── Logotype 2.png ├── Logotype 2_black.png └── Logotype 2_white.png ├── install └── fastotv │ ├── CHANGELOG │ ├── COPYRIGHT │ ├── android │ ├── AndroidManifest.xml.in │ ├── configAndroid.json.in │ ├── icon.png │ ├── res │ │ ├── drawable-hdpi │ │ │ └── icon.png │ │ ├── drawable-ldpi │ │ │ └── icon.png │ │ ├── drawable-mdpi │ │ │ └── icon.png │ │ └── drawable-xhdpi │ │ │ └── icon.png │ └── strings.xml.in │ ├── autostart.sh.in │ ├── config.ini.in │ ├── desktop.in │ ├── fonts │ └── FreeSans.ttf │ ├── hardware │ └── lirc │ │ └── lircrc.conf.in │ ├── linux │ ├── gentoo.ebuild.in │ ├── icon.png │ ├── postinst.in │ ├── prerm.in │ └── xinitrc.in │ ├── macosx │ └── icon.icns │ ├── resources │ ├── connection_error.png │ ├── down_arrow.png │ ├── left_arrow.png │ ├── offline_channel.png │ ├── right_arrow.png │ ├── unknown_channel.png │ └── up_arrow.png │ └── windows │ ├── database.bmp │ ├── icon.ico │ ├── nsis-top-logo.bmp │ └── winres.rc.in ├── scripts ├── create_pre_commit_hook.sh └── pre-commit ├── src ├── CMakeLists.txt ├── client │ ├── cmdutils.cpp │ ├── cmdutils.h │ ├── events │ │ ├── network_events.cpp │ │ └── network_events.h │ ├── inner │ │ ├── inner_tcp_handler.cpp │ │ ├── inner_tcp_handler.h │ │ ├── inner_tcp_server.cpp │ │ └── inner_tcp_server.h │ ├── inputs │ │ ├── lirc_input_client.cpp │ │ └── lirc_input_client.h │ ├── ioservice.cpp │ ├── ioservice.h │ ├── live_stream │ │ ├── playlist_entry.cpp │ │ ├── playlist_entry.h │ │ ├── playlist_window.cpp │ │ └── playlist_window.h │ ├── load_config.cpp │ ├── load_config.h │ ├── player.cpp │ ├── player.h │ ├── programs_window.cpp │ ├── programs_window.h │ ├── tv_player_main.cpp │ ├── utils.cpp │ ├── utils.h │ ├── vod │ │ ├── vod_entry.cpp │ │ ├── vod_entry.h │ │ ├── vods_window.cpp │ │ └── vods_window.h │ ├── vods_window.cpp │ └── vods_window.h └── third-party │ └── ini │ └── CMakeLists.txt └── tests └── unit_tests └── test_commands.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Chromium 3 | ColumnLimit: 120 4 | Standard: Cpp11 5 | ... 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | # other 32 | *.pyc 33 | CMakeLists.txt.user 34 | *~ 35 | 36 | # fastogt tmp files 37 | build/.idea/ 38 | build_cmake/ 39 | .idea/ 40 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cmake"] 2 | path = cmake 3 | url = https://github.com/fastogt/cmake.git 4 | [submodule "src/third-party/ini/inih"] 5 | path = src/third-party/ini/inih 6 | url = https://github.com/benhoyt/inih.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.3.0) # deb package fix in 3.3.0 2 | ###################### Branding ########################## 3 | 4 | SET(BRANDING_PROJECT_NAME "FastoTV" CACHE STRING "Branding for ${BRANDING_PROJECT_NAME}") #default 5 | SET(BRANDING_PROJECT_VERSION "1.25.0.60" CACHE STRING "Branding version for ${BRANDING_PROJECT_NAME}") #default 6 | SET(BRANDING_PROJECT_BUILD_TYPE_VERSION "release" CACHE STRING "Build version type for ${BRANDING_PROJECT_NAME}") #default 7 | #possible variables: alfa, beta, rc, release 8 | 9 | SET(BRANDING_PROJECT_DOMAIN "https://fastotv.com" CACHE STRING "Branding domain url for ${BRANDING_PROJECT_NAME}") #default 10 | SET(BRANDING_PROJECT_DOWNLOAD_LINK "https://fastotv.com/downloads" CACHE STRING "Branding download root url for ${BRANDING_PROJECT_NAME}") 11 | SET(BRANDING_PROJECT_COMPANYNAME "FastoGT" CACHE STRING "Company name for ${BRANDING_PROJECT_NAME}") #default 12 | SET(BRANDING_PROJECT_COMPANYNAME_DOMAIN "https://fastogt.com" CACHE STRING "Internet domain name company for ${BRANDING_PROJECT_NAME}") #default 13 | SET(BRANDING_PROJECT_MAINTAINER_MAIL "atopilski@fastogt.com" CACHE STRING "Internet mail address maintainer of ${BRANDING_PROJECT_NAME}") #default 14 | SET(BRANDING_PROJECT_MAINTAINER_NAME "Alexandr Topilski" CACHE STRING "Name of maintainer for ${BRANDING_PROJECT_NAME}") #default 15 | 16 | SET(BRANDING_PROJECT_GITHUB_FORK "https://github.com/fastogt/fastotv" CACHE STRING "Branding fork url for ${BRANDING_PROJECT_NAME}") #default 17 | SET(BRANDING_PROJECT_GITHUB_ISSUES "https://github.com/fastogt/fastotv/issues" CACHE STRING "Branding issues url for ${BRANDING_PROJECT_NAME}") #default 18 | 19 | SET(BRANDING_PROJECT_HOMEPAGE_LINK "https://fastotv.com" CACHE STRING "Home page link for ${BRANDING_PROJECT_NAME}") #default 20 | SET(BRANDING_PROJECT_FACEBOOK_LINK "https://facebook.com/profile.php?id=100016809641223" CACHE STRING "FaceBook link for ${BRANDING_PROJECT_NAME}") #default 21 | SET(BRANDING_PROJECT_TWITTER_LINK "https://twitter.com/FastoTv" CACHE STRING "Twitter link for ${BRANDING_PROJECT_NAME}") #default 22 | SET(BRANDING_PROJECT_GITHUB_LINK "https://github.com/fastogt/fastotv" CACHE STRING "GitHub link for ${BRANDING_PROJECT_NAME}") #default 23 | 24 | SET(BRANDING_PROJECT_SUMMARY "Cross-platform open source TV player." CACHE STRING "Short description of ${BRANDING_PROJECT_NAME}") 25 | SET(BRANDING_PROJECT_DESCRIPTION "${BRANDING_PROJECT_NAME} it is TV player." CACHE STRING "Description of ${BRANDING_PROJECT_NAME}") 26 | SET(BRANDING_PROJECT_COPYRIGHT "Copyright (C) 2014-2022 ${BRANDING_PROJECT_COMPANYNAME} All Rights Reserved." CACHE STRING "Copyright notice for ${BRANDING_PROJECT_NAME}") #default 27 | 28 | PROJECT(${BRANDING_PROJECT_NAME} VERSION ${BRANDING_PROJECT_VERSION} LANGUAGES CXX C) 29 | SET(CMAKE_CXX_STANDARD 14) 30 | SET(CMAKE_CXX_STANDARD_REQUIRED ON) 31 | SET(CMAKE_CXX_EXTENSIONS OFF) 32 | SET(CMAKE_C_STANDARD 99) 33 | SET(CMAKE_C_STANDARD_REQUIRED ON) 34 | #SET(CMAKE_C_EXTENSIONS OFF) 35 | #################### Project Settings #################### 36 | SET(PROJECT_NAME_TITLE ${PROJECT_NAME}) #PROJECT_NAME in cache 37 | SET(PROJECT_DOMAIN ${BRANDING_PROJECT_DOMAIN}) 38 | SET(PROJECT_DOWNLOAD_LINK ${BRANDING_PROJECT_DOWNLOAD_LINK}) 39 | SET(PROJECT_COMPANYNAME ${BRANDING_PROJECT_COMPANYNAME}) 40 | SET(PROJECT_COPYRIGHT ${BRANDING_PROJECT_COPYRIGHT}) 41 | SET(PROJECT_SUMMARY ${BRANDING_PROJECT_SUMMARY}) 42 | SET(PROJECT_DESCRIPTION ${BRANDING_PROJECT_DESCRIPTION}) 43 | SET(PROJECT_COMPANYNAME_DOMAIN ${BRANDING_PROJECT_COMPANYNAME_DOMAIN}) 44 | SET(PROJECT_MAINTAINER_MAIL ${BRANDING_PROJECT_MAINTAINER_MAIL}) 45 | SET(PROJECT_MAINTAINER_NAME ${BRANDING_PROJECT_MAINTAINER_NAME}) 46 | SET(PROJECT_GITHUB_FORK ${BRANDING_PROJECT_GITHUB_FORK}) 47 | SET(PROJECT_GITHUB_ISSUES ${BRANDING_PROJECT_GITHUB_ISSUES}) 48 | 49 | SET(PROJECT_BUILD_TYPE_VERSION ${BRANDING_PROJECT_BUILD_TYPE_VERSION}) 50 | SET(PROJECT_HOMEPAGE_LINK ${BRANDING_PROJECT_HOMEPAGE_LINK}) 51 | SET(PROJECT_FACEBOOK_LINK ${BRANDING_PROJECT_FACEBOOK_LINK}) 52 | SET(PROJECT_TWITTER_LINK ${BRANDING_PROJECT_TWITTER_LINK}) 53 | SET(PROJECT_GITHUB_LINK ${BRANDING_PROJECT_GITHUB_LINK}) 54 | ########################################################## 55 | 56 | STRING(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE) 57 | STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERRCASE) 58 | 59 | SET(PROJECT_BRANDING_FOLDER ${CMAKE_SOURCE_DIR}/install/${PROJECT_NAME_LOWERCASE}) 60 | SET(PROJECT_VERSION_SHORT ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) #PROJECT_VERSION_* in cache 61 | SET(PROJECT_VERSION_INTEGER ${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}${PROJECT_VERSION_PATCH}) #PROJECT_VERSION_* in cache 62 | 63 | MESSAGE(STATUS "PROJECT_VERSION: ${PROJECT_VERSION}") 64 | 65 | SET(PROJECT_CHANGELOG_FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/CHANGELOG) 66 | SET(DATE_CMD "date") 67 | SET(DATE_ARGS "+%a %b %d %Y") 68 | EXECUTE_PROCESS(COMMAND ${DATE_CMD} ${DATE_ARGS} RESULT_VARIABLE CHANGELOG_TIMESTAMP_RESULT OUTPUT_VARIABLE CHANGELOG_TIMESTAMP) #for rpm package 69 | IF (NOT "${CHANGELOG_TIMESTAMP}" STREQUAL "") 70 | STRING(REPLACE "\n" "" CHANGELOG_TIMESTAMP ${CHANGELOG_TIMESTAMP}) 71 | ELSE() 72 | MESSAGE(WARNING "Failed to get timestamp: ${CHANGELOG_TIMESTAMP_RESULT}") 73 | ENDIF(NOT "${CHANGELOG_TIMESTAMP}" STREQUAL "") 74 | FILE(WRITE ${PROJECT_CHANGELOG_FILE} "* ${CHANGELOG_TIMESTAMP} ${PROJECT_MAINTAINER_NAME} <${PROJECT_MAINTAINER_MAIL}>\n") 75 | FILE(READ ${PROJECT_BRANDING_FOLDER}/CHANGELOG CHANGELOG_TEXT) 76 | FILE(APPEND ${PROJECT_CHANGELOG_FILE} ${CHANGELOG_TEXT}) 77 | 78 | IF(APPLE AND CMAKE_OSX_SYSROOT) 79 | STRING(REGEX REPLACE ".*MacOSX([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_SDK_VERSION "${CMAKE_OSX_SYSROOT}") 80 | STRING(REGEX REPLACE ".*MacOSX([0-9]+)\\.([0-9]+).*$" "\\2" DARWIN_MINOR_SDK_VERSION "${CMAKE_OSX_SYSROOT}") 81 | IF(EXISTS "${CMAKE_OSX_SYSROOT}") 82 | SET(MACOSX_DEPLOYMENT_TARGET ${DARWIN_MAJOR_SDK_VERSION}.${DARWIN_MINOR_SDK_VERSION}) 83 | SET(CMAKE_CXX_FLAGS "--sysroot ${CMAKE_OSX_SYSROOT} ${CMAKE_CXX_FLAGS}") 84 | MESSAGE(STATUS "Setting MACOSX_DEPLOYMENT_TARGET to '${MACOSX_DEPLOYMENT_TARGET}'.") 85 | ENDIF() 86 | ENDIF(APPLE AND CMAKE_OSX_SYSROOT) 87 | 88 | ########################## Options ######################### 89 | OPTION(CPACK_SUPPORT "Enable package support" ON) 90 | OPTION(LOG_TO_FILE "Logging to file" OFF) 91 | OPTION(DEVELOPER_ENABLE_TESTS "Enable tests for ${PROJECT_NAME_TITLE} project" OFF) 92 | OPTION(DEVELOPER_CHECK_STYLE "Enable check style for ${PROJECT_NAME_TITLE} project" OFF) 93 | OPTION(DEVELOPER_GENERATE_DOCS "Generate docs api for ${PROJECT_NAME_TITLE} project" OFF) 94 | IF (DEVELOPER_ENABLE_TESTS) 95 | OPTION(DEVELOPER_ENABLE_UNIT_TESTS "Enable tests for ${PROJECT_NAME_TITLE} project" ON) 96 | ENDIF(DEVELOPER_ENABLE_TESTS) 97 | ##################################DEFAULT VALUES########################################## 98 | IF(NOT CMAKE_BUILD_TYPE) 99 | SET(CMAKE_BUILD_TYPE DEBUG) 100 | ENDIF(NOT CMAKE_BUILD_TYPE) 101 | 102 | # If the user did not customize the install prefix, 103 | # set it to live under build so we don't inadvertently pollute /usr/local 104 | IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 105 | SET(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "default install path" FORCE) 106 | ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 107 | 108 | IF("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") 109 | MESSAGE(SEND_ERROR "In-source builds are not allowed.") 110 | ENDIF("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") 111 | 112 | MESSAGE(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") 113 | 114 | ############################################################################ 115 | 116 | SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake") 117 | INCLUDE(config) ################### 118 | DEFINE_DEFAULT_DEFINITIONS(OFF ON OFF) 119 | DEFINE_PROJECT_DEFINITIONS() 120 | 121 | ########################################################## 122 | 123 | # pwd + RELATIVE_SOURCE_DIR = install directory 124 | IF(OS_WINDOWS) 125 | SET(LIB_INSTALL_DESTINATION .) 126 | SET(TARGET_INSTALL_DESTINATION .) 127 | SET(SHARE_INSTALL_DESTINATION share) 128 | SET(RELATIVE_SOURCE_DIR .) 129 | SET(EXECUTABLE_NAME ${PROJECT_NAME}.exe) 130 | ELSEIF(OS_MACOSX) 131 | SET(BUNDLE_BASE_NAME ${PROJECT_NAME}) 132 | SET(BUNDLE_NAME ${BUNDLE_BASE_NAME}.app) 133 | SET(LIB_INSTALL_DESTINATION .) 134 | SET(TARGET_INSTALL_DESTINATION .) 135 | SET(SHARE_INSTALL_DESTINATION ${BUNDLE_NAME}/Contents/share) 136 | SET(RELATIVE_SOURCE_DIR Contents) 137 | SET(EXECUTABLE_NAME ${BUNDLE_NAME}) 138 | ELSEIF(OS_LINUX) 139 | SET(LIB_INSTALL_DESTINATION lib) 140 | SET(TARGET_INSTALL_DESTINATION bin) 141 | SET(SHARE_INSTALL_DESTINATION share) 142 | SET(RELATIVE_SOURCE_DIR ..) 143 | SET(EXECUTABLE_NAME ${PROJECT_NAME}) 144 | ELSEIF(OS_FREEBSD) 145 | SET(LIB_INSTALL_DESTINATION lib) 146 | SET(TARGET_INSTALL_DESTINATION bin) 147 | SET(SHARE_INSTALL_DESTINATION share) 148 | SET(RELATIVE_SOURCE_DIR ..) 149 | SET(EXECUTABLE_NAME ${PROJECT_NAME}) 150 | ELSEIF(OS_ANDROID) 151 | SET(LIB_INSTALL_DESTINATION libs/${ANDROID_NDK_ABI_NAME}) 152 | SET(TARGET_INSTALL_DESTINATION libs/${ANDROID_NDK_ABI_NAME}) #libs/armeabi-v7a 153 | SET(SHARE_INSTALL_DESTINATION libs/${ANDROID_NDK_ABI_NAME/share) 154 | SET(RELATIVE_SOURCE_DIR .) 155 | ENDIF(OS_WINDOWS) 156 | 157 | ADD_DEFINITIONS(-DRELATIVE_SOURCE_DIR="${RELATIVE_SOURCE_DIR}") 158 | 159 | # project sources 160 | SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) 161 | 162 | IF(LOG_TO_FILE) 163 | ADD_DEFINITIONS(-DLOG_TO_FILE) 164 | ENDIF(LOG_TO_FILE) 165 | 166 | ADD_DEFINITIONS( 167 | -DPROJECT_SUMMARY="${PROJECT_SUMMARY}" 168 | -DPROJECT_DESCRIPTION="${PROJECT_DESCRIPTION}" 169 | -DPROJECT_GITHUB_FORK="${PROJECT_GITHUB_FORK}" 170 | -DPROJECT_GITHUB_ISSUES="${PROJECT_GITHUB_ISSUES}" 171 | -DPROJECT_DOWNLOAD_LINK="${PROJECT_DOWNLOAD_LINK}" 172 | ) 173 | 174 | SET(PROJECT_VERSION_HUMAN "${PROJECT_VERSION} ${PROJECT_BUILD_TYPE_VERSION} Revision: ${PROJECT_VERSION_GIT}") 175 | ADD_DEFINITIONS(-DPROJECT_VERSION_HUMAN="${PROJECT_VERSION_HUMAN}") 176 | 177 | ADD_SUBDIRECTORY(src) 178 | 179 | #CPACK 180 | IF(CPACK_SUPPORT) 181 | SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_SUMMARY} ${PROJECT_NAME}") 182 | SET(CPACK_PACKAGE_DESCRIPTION ${PROJECT_DESCRIPTION}) 183 | # CPACK_DEBIAN_PACKAGE_DESCRIPTION CPACK_RPM_PACKAGE_SUMMARY 184 | SET(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_BRANDING_FOLDER}/COPYRIGHT")#CPACK_RPM_PACKAGE_DESCRIPTION 185 | SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") 186 | SET(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md") 187 | SET(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/README.md") 188 | 189 | SET(CPACK_PACKAGE_VENDOR "${PROJECT_COMPANYNAME}")#CPACK_RPM_PACKAGE_VENDOR 190 | SET(CPACK_PACKAGE_CONTACT "${PROJECT_MAINTAINER_NAME} <${PROJECT_MAINTAINER_MAIL}>")#CPACK_DEBIAN_PACKAGE_MAINTAINER 191 | 192 | SET(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) 193 | SET(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) 194 | SET(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_SHORT}) 195 | 196 | IF(NOT PROJECT_BUILD_TYPE_VERSION STREQUAL "release") 197 | SET(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}-${PROJECT_BUILD_TYPE_VERSION}${PROJECT_VERSION_TWEAK}") 198 | ENDIF(NOT PROJECT_BUILD_TYPE_VERSION STREQUAL "release") 199 | 200 | SET(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_PATCH})#CPACK_DEBIAN_PACKAGE_VERSION CPACK_RPM_PACKAGE_VERSION 201 | SET(CPACK_PACKAGE_NAME ${PROJECT_NAME_LOWERCASE})#CPACK_DEBIAN_PACKAGE_NAME CPACK_RPM_PACKAGE_NAME 202 | SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${PLATFORM_ARCH_FULL_NAME}-${PROJECT_VERSION_GIT}")#out package name 203 | SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}") 204 | SET(CPACK_PACKAGE_INSTALL_DIRECTORY ${PROJECT_NAME}) 205 | SET(CPACK_PACKAGE_EXECUTABLES "${PROJECT_NAME_TITLE};${PROJECT_NAME}") 206 | MESSAGE(STATUS "CPACK_PACKAGE_FILE_NAME: ${CPACK_PACKAGE_FILE_NAME}") 207 | SET(CPACK_MONOLITHIC_INSTALL ON) 208 | 209 | IF(OS_WINDOWS) 210 | #NSIS 211 | IF(PLATFORM_X86_64) 212 | SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") 213 | ELSE() 214 | SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") 215 | ENDIF(PLATFORM_X86_64) 216 | # There is a bug in NSI that does not handle full unix paths properly. Make 217 | # sure there is at least one set of four (4) backslashes. 218 | # SET(CPACK_NSIS_MODIFY_PATH ON) 219 | SET(CPACK_PACKAGE_ICON "${PROJECT_BRANDING_FOLDER}/windows\\\\nsis-top-logo.bmp") 220 | SET(CPACK_NSIS_INSTALLED_ICON_NAME "\\\\${PROJECT_NAME}.exe") 221 | SET(CPACK_CREATE_DESKTOP_LINKS "${PROJECT_NAME}.exe") 222 | SET(CPACK_NSIS_CREATE_ICONS "CreateShortCut \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\${PROJECT_NAME}.lnk\\\" \\\"$INSTDIR\\\\${PROJECT_NAME}.exe\\\"") 223 | SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut \\\"$DESKTOP\\\\${PROJECT_NAME}.lnk\\\" \\\"$INSTDIR\\\\${PROJECT_NAME}.exe\\\"") 224 | SET(CPACK_NSIS_DELETE_ICONS_EXTRA "Delete \\\"$DESKTOP\\\\${PROJECT_NAME}.lnk\\\"") 225 | SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}") 226 | SET(CPACK_NSIS_HELP_LINK "${PROJECT_COMPANYNAME_DOMAIN}") 227 | SET(CPACK_NSIS_URL_INFO_ABOUT "${PROJECT_DOMAIN}") 228 | SET(SIDEBAR_IMAGE ${PROJECT_BRANDING_FOLDER}/windows\\\\database.bmp) 229 | SET(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "!define MUI_WELCOMEFINISHPAGE_BITMAP \\\"${SIDEBAR_IMAGE}\\\"") 230 | SET(CPACK_NSIS_CONTACT "me@my-personal-home-page.com") 231 | SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "..\\\\${PROJECT_NAME}.exe") 232 | ELSEIF(OS_MACOSX) 233 | # SET(CPACK_OSX_PACKAGE_VERSION "10.5") 234 | ELSEIF(OS_LINUX) 235 | SET(CPACK_STRIP_FILES ON) 236 | #SET(UBUNTU_LP_BUG 300472) 237 | #SET(CPACK_STRIP_FILES "bin/${PROJECT_NAME}") 238 | #SET(CPACK_SOURCE_STRIP_FILES "") 239 | 240 | SET(CPACK_PACKAGING_INSTALL_PREFIX "/opt/${PROJECT_NAME_LOWERCASE}") 241 | 242 | SET(FIXED_SCRIPT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}") 243 | 244 | SET(POST_INSTALL_SCRIPT_GENERATED_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/scripts/postinst") 245 | SET(POST_INSTALL_SCRIPT_GENERATED_FIXED_PATH ${FIXED_SCRIPT_DESTINATION}/postinst) 246 | CONFIGURE_FILE("${PROJECT_BRANDING_FOLDER}/linux/postinst.in" ${POST_INSTALL_SCRIPT_GENERATED_PATH} @ONLY IMMEDIATE) 247 | FILE(COPY ${POST_INSTALL_SCRIPT_GENERATED_PATH} DESTINATION ${FIXED_SCRIPT_DESTINATION} 248 | FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) 249 | 250 | SET(PRE_UNINSTALL_SCRIPT_GENERATED_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/scripts/prerm") 251 | SET(PRE_UNINSTALL_SCRIPT_GENERATED_FIXED_PATH ${FIXED_SCRIPT_DESTINATION}/prerm) 252 | CONFIGURE_FILE("${PROJECT_BRANDING_FOLDER}/linux/prerm.in" ${PRE_UNINSTALL_SCRIPT_GENERATED_PATH} @ONLY IMMEDIATE) 253 | FILE(COPY ${PRE_UNINSTALL_SCRIPT_GENERATED_PATH} DESTINATION ${FIXED_SCRIPT_DESTINATION} 254 | FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) 255 | 256 | #RPM 257 | # CPACK_RPM_PACKAGE_ARCHITECTURE CPACK_RPM_PACKAGE_LICENSE CPACK_RPM_PACKAGE_DESCRIPTION CPACK_RPM_SPEC_INSTALL_POST 258 | # SET(CPACK_PACKAGE_RELEASE 1) 259 | SET(CPACK_RPM_PACKAGE_LICENSE "GPL v3") 260 | SET(CPACK_RPM_PACKAGE_AUTOREQPROV "no") 261 | SET(CPACK_RPM_PACKAGE_REQUIRES "libstdc++, xorg-x11-xinit") 262 | SET(CPACK_RPM_PACKAGE_RELEASE 1) 263 | SET(CPACK_RPM_PACKAGE_GROUP "Development/video") 264 | SET(CPACK_RPM_PACKAGE_ARCHITECTURE ${PLATFORM_PACKAGE_ARCH_NAME}) 265 | SET(CPACK_RPM_PACKAGE_VERSION ${PROJECT_VERSION_SHORT}) 266 | SET(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${POST_INSTALL_SCRIPT_GENERATED_FIXED_PATH}) 267 | SET(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE ${PRE_UNINSTALL_SCRIPT_GENERATED_FIXED_PATH}) 268 | SET(CPACK_RPM_CHANGELOG_FILE ${PROJECT_CHANGELOG_FILE}) 269 | #DEB 270 | # SET(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) 271 | # CPACK_DEBIAN_PACKAGE_HOMEPAGE The URL of the web site for this package 272 | # SET(CPACK_DEBIAN_PACKAGE_DEBUG ON) 273 | # libva-drm1 (>= 1.1.0), libva-x11-1 (>= 1.0.3), libvdpau1 (>= 0.2), xinit 274 | SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11), libstdc++6 (>= 4.8.2)") 275 | SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") 276 | SET(CPACK_DEBIAN_PACKAGE_SECTION "video") #input our section 277 | SET(CPACK_DEBIAN_PACKAGE_RECOMMENDS "Unknown") 278 | SET(CPACK_DEBIAN_PACKAGE_SUGGESTS "Unknown") 279 | SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${PLATFORM_PACKAGE_ARCH_NAME})#i386 280 | SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${POST_INSTALL_SCRIPT_GENERATED_FIXED_PATH};${PRE_UNINSTALL_SCRIPT_GENERATED_FIXED_PATH}") 281 | ELSEIF(OS_ANDROID) 282 | ENDIF(OS_WINDOWS) 283 | INCLUDE(CPack) 284 | ENDIF(CPACK_SUPPORT) 285 | 286 | #DOCS 287 | IF(DEVELOPER_GENERATE_DOCS) 288 | CREATE_DOCS(${PROJECT_NAME_LOWERCASE} ${CMAKE_SOURCE_DIR}/docs/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) 289 | ENDIF(DEVELOPER_GENERATE_DOCS) 290 | 291 | IF(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit) 292 | EXECUTE_PROCESS(COMMAND ${CMAKE_SOURCE_DIR}/scripts/create_pre_commit_hook.sh) 293 | ENDIF(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit) 294 | -------------------------------------------------------------------------------- /CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | # This is the toplevel CPPLINT.cfg file 2 | set noparent 3 | 4 | linelength=120 5 | root=src 6 | 7 | filter=-runtime/int 8 | filter=-build/include_order 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![512 px_horizontal-01](https://user-images.githubusercontent.com/36637989/43616278-a089589e-96b3-11e8-8bc2-60615366e442.png) 2 | 3 | About FastoTV 4 | =============== 5 | [![Travis Build Status](https://travis-ci.org/fastogt/gpu_player.svg?branch=master)](https://travis-ci.org/fastogt/fastotv) 6 | [![GitHub license](https://img.shields.io/badge/license-GPLv3-blue.svg)](https://raw.githubusercontent.com/fastogt/fastotv/master/COPYRIGHT) 7 | 8 | FastoTV - is a crossplatform free iptv/stream player.
9 | 10 | ### PC/RaspberryPI/BananaPI/OrangePI: 11 | ![](https://fastotv.com/app/api/static/images/promo/pc.png) 12 | 13 | ### Android Mobile/Tablet: 14 | ![](https://fastotv.com/app/api/static/images/promo/android.png) 15 | 16 | ### Android TV: 17 | ![](https://fastotv.com/app/api/static/images/promo/android_tv.png) 18 | 19 | ### iPhone: 20 | ![](https://fastotv.com/app/api/static/images/promo/iphone.jpeg) 21 | 22 | ### iPad: 23 | ![](https://fastotv.com/app/api/static/images/promo/ipad.png) 24 | 25 | Visit our site: [FastoTV](https://crocott.com) 26 | 27 | Download 28 | ======== 29 | 30 | You can download compiled version (for Mac OS X, Windows, FreeBSD and Linux) from our site:
31 | [CrocOTT](https://crocott.com) 32 | 33 | ### [Android PlayStore](https://play.google.com/store/apps/details?id=com.crocott) 34 | ### [Apple Store](https://apps.apple.com/us/app/crocott/id1642691103) 35 | 36 | Contribute 37 | ========== 38 | Contributions are always welcome! Just try to follow our coding style: [FastoGT Coding Style](https://github.com/fastogt/fastonosql/wiki/Coding-Style) 39 | 40 | Build 41 | ===== 42 | 43 | Build documentation: [Build FastoTV](https://github.com/fastogt/fastotv/wiki/Build) 44 | 45 | License 46 | ======= 47 | 48 | Copyright (c) 2014-2022 FastoGT (https://fastogt.com) 49 | 50 | This program is free software: you can redistribute it and/or modify 51 | it under the terms of the GNU General Public License version 3 as 52 | published by the Free Software Foundation. 53 | 54 | This program is distributed in the hope that it will be useful, 55 | but WITHOUT ANY WARRANTY; without even the implied warranty of 56 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 57 | GNU General Public License for more details. 58 | 59 | You should have received a copy of the GNU General Public License 60 | along with this program. If not, see . 61 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | build_* 2 | config.py 3 | -------------------------------------------------------------------------------- /build/brands/fastotv/fastotv.txt: -------------------------------------------------------------------------------- 1 | -DBRANDING_PROJECT_BUILD_TYPE_VERSION:STRING=release 2 | -DBRANDING_PROJECT_SUMMARY:STRING=Cross-platform open source IPTV player. 3 | -DBRANDING_PROJECT_DESCRIPTION:STRING=Cross-platform open source IPTV player. 4 | -------------------------------------------------------------------------------- /build/build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import re 4 | import shutil 5 | import sys 6 | 7 | from pyfastogt import run_command 8 | from pyfastogt import system_info 9 | from pyfastogt import utils, build_utils 10 | 11 | 12 | def print_usage(): 13 | print("Usage:\n" 14 | "[required] argv[1] cmake_root_path\n" 15 | "[optional] argv[2] branding_file_path\n" 16 | "[optional] argv[3] platform\n" 17 | "[optional] argv[4] architecture\n" 18 | "[optional] argv[5] build system(\"ninja\", \"make\", \"gmake\")\n" 19 | "[optional] argv[6] packages for example(\"DEB RPM\")\n") 20 | 21 | 22 | class BuildSystem: 23 | def __init__(self, name, cmd_line: list, cmake_generator_arg, policy: run_command.Policy): 24 | self.name_ = name 25 | self.cmd_line_ = cmd_line 26 | self.cmake_generator_arg_ = cmake_generator_arg 27 | self.policy_ = policy 28 | 29 | def cmake_generator_arg(self) -> str: 30 | return self.cmake_generator_arg_ 31 | 32 | def name(self) -> str: 33 | return self.name_ 34 | 35 | def policy(self) -> run_command.Policy: 36 | return self.policy_ 37 | 38 | def cmd_line(self) -> list: # cmd + args 39 | return self.cmd_line_ 40 | 41 | 42 | SUPPORTED_BUILD_SYSTEMS = [BuildSystem('ninja', ['ninja'], '-GNinja', run_command.NinjaPolicy), 43 | BuildSystem('make', ['make', '-j2'], '-GUnix Makefiles', run_command.MakePolicy)] 44 | 45 | 46 | def get_supported_build_system_by_name(name): 47 | return next((x for x in SUPPORTED_BUILD_SYSTEMS if x.name() == name), None) 48 | 49 | 50 | def print_message(progress, message): 51 | print('{0:.1f}% {1}'.format(progress, message)) 52 | sys.stdout.flush() 53 | 54 | 55 | class ProgressSaver(object): 56 | def __init__(self, cb): 57 | self.progress_min_ = 0.0 58 | self.progress_max_ = 0.0 59 | self.cb_ = cb 60 | 61 | def update_progress_message_range(self, progress_min, progress_max, message): 62 | self.progress_min_ = progress_min 63 | self.progress_max_ = progress_max 64 | if self.cb_: 65 | self.cb_(progress_min, message) 66 | 67 | def on_update_progress_message(self, progress, message): 68 | if message.type() == run_command.MessageType.STATUS: 69 | return 70 | 71 | diff = self.progress_max_ - self.progress_min_ 72 | perc = self.progress_min_ + diff * (progress / 100.0) 73 | if self.cb_: 74 | self.cb_(perc, message.message()) 75 | 76 | 77 | class BuildRequest(object): 78 | def __init__(self, platform, arch_name): 79 | platform_or_none = system_info.get_supported_platform_by_name(platform) 80 | 81 | if not platform_or_none: 82 | raise build_utils.BuildError('invalid platform') 83 | 84 | arch = platform_or_none.get_architecture_by_arch_name(arch_name) 85 | if not arch: 86 | raise build_utils.BuildError('invalid arch') 87 | 88 | self.platform_ = platform_or_none.make_platform_by_arch(arch, platform_or_none.package_types()) 89 | print("Build request for platform: {0}, arch: {1} created".format(platform, arch.name())) 90 | 91 | def platform(self): 92 | return self.platform_ 93 | 94 | def build(self, cmake_project_root_path: str, branding_options: list, dir_path: str, bs: BuildSystem, 95 | package_types: list, 96 | saver: ProgressSaver): 97 | cmake_project_root_abs_path = os.path.abspath(cmake_project_root_path) 98 | if not os.path.exists(cmake_project_root_abs_path): 99 | raise build_utils.BuildError('invalid cmake_project_root_path: %s' % cmake_project_root_path) 100 | 101 | if not bs: 102 | bs = SUPPORTED_BUILD_SYSTEMS[0] 103 | 104 | if not package_types: 105 | package_types = self.platform_.package_types() 106 | 107 | abs_dir_path = os.path.abspath(dir_path) 108 | if os.path.exists(abs_dir_path): 109 | shutil.rmtree(abs_dir_path) 110 | 111 | generator = bs.cmake_generator_arg() 112 | build_system_args = bs.cmd_line() 113 | build_system_policy = bs.policy() 114 | 115 | saver.update_progress_message_range(0.0, 9.0, "Start building project branding_options:\n{0}".format( 116 | "\n".join(branding_options))) 117 | 118 | pwd = os.getcwd() 119 | os.mkdir(abs_dir_path) 120 | os.chdir(abs_dir_path) 121 | 122 | # project static options 123 | log_to_file_args = '-DLOG_TO_FILE=ON' 124 | openssl_args = '-DOPENSSL_USE_STATIC_LIBS=ON' 125 | jsonc_args = '-DJSONC_USE_STATIC=ON' 126 | libev_args = '-DLIBEV_USE_STATIC=ON' 127 | 128 | cmake_line = ['cmake', cmake_project_root_abs_path, generator, '-DCMAKE_BUILD_TYPE=RELEASE', openssl_args, 129 | jsonc_args, log_to_file_args, libev_args] 130 | 131 | if branding_options: 132 | cmake_line.extend(branding_options) 133 | 134 | saver.update_progress_message_range(10.0, 19.0, 'Generate project build') 135 | 136 | def store_closure(cb): 137 | def closure(progress, message): 138 | return cb(progress, message) 139 | 140 | return closure 141 | 142 | store = store_closure(saver.on_update_progress_message) 143 | 144 | try: 145 | cmake_policy = run_command.CmakePolicy(store) 146 | run_command.run_command_cb(cmake_line, cmake_policy) 147 | except Exception as ex: 148 | os.chdir(pwd) 149 | raise ex 150 | 151 | make_install = build_system_args 152 | make_install.append('install') 153 | saver.update_progress_message_range(20.0, 79.0, 'Build project') 154 | try: 155 | policy = build_system_policy(store) 156 | run_command.run_command_cb(make_install, policy) 157 | except Exception as ex: 158 | os.chdir(pwd) 159 | raise ex 160 | 161 | saver.update_progress_message_range(80.0, 84.0, 'Trying to get package file name') 162 | in_file = open('CPackConfig.cmake', 'r') 163 | for line in in_file.readlines(): 164 | res = re.search(r'SET\(CPACK_PACKAGE_FILE_NAME "(.+)"\)', line) 165 | if res: 166 | filename = res.group(1) 167 | break 168 | in_file.close() 169 | 170 | saver.update_progress_message_range(85.0, 99.0, 'Start build package') 171 | file_names = [] 172 | for generator in package_types: 173 | make_cpack = ['cpack', '-G', generator] 174 | try: 175 | common_policy = run_command.CommonPolicy(store) 176 | run_command.run_command_cb(make_cpack, common_policy) 177 | file_names.append( 178 | os.path.join(abs_dir_path, filename + '.' + system_info.get_extension_by_package(generator))) 179 | except Exception as ex: 180 | os.chdir(pwd) 181 | raise ex 182 | 183 | os.chdir(pwd) 184 | 185 | saver.update_progress_message_range(100.0, 100.0, 186 | "Building finished successfully file_names: {0}".format(file_names)) 187 | return file_names 188 | 189 | 190 | if __name__ == "__main__": 191 | argc = len(sys.argv) 192 | dev_null = '/dev/null' 193 | 194 | if argc > 1: 195 | cmake_root = sys.argv[1] 196 | else: 197 | print_usage() 198 | sys.exit(1) 199 | 200 | if argc > 2: 201 | branding_file_path = sys.argv[2] 202 | else: 203 | branding_file_path = 'brands/fastotv/fastotv.txt' 204 | 205 | if argc > 3: 206 | platform_str = sys.argv[3] 207 | else: 208 | platform_str = system_info.get_os() 209 | 210 | if argc > 4: 211 | arch_name_str = sys.argv[4] 212 | else: 213 | arch_name_str = system_info.get_arch_name() 214 | 215 | if argc > 5: 216 | bs_str = sys.argv[5] 217 | bs = get_supported_build_system_by_name(bs_str) 218 | else: 219 | bs = [] 220 | 221 | if argc > 6: 222 | packages = sys.argv[6].split() 223 | else: 224 | packages = [] 225 | 226 | request = BuildRequest(platform_str, arch_name_str) 227 | abs_branding_file = os.path.abspath(branding_file_path) 228 | args_branding_options = utils.read_file_line_by_line_to_list(abs_branding_file) 229 | 230 | saver = ProgressSaver(print_message) 231 | request.build(cmake_root, args_branding_options, 'build_' + platform_str, bs, packages, saver) 232 | -------------------------------------------------------------------------------- /build/build_server_remote.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | import shlex 4 | import sys 5 | 6 | import build 7 | import config 8 | import pika 9 | from pyfastogt import system_info, build_utils 10 | 11 | 12 | def gen_routing_key(device, platform, arch) -> str: 13 | return device + '_' + platform + '_' + arch 14 | 15 | 16 | def print_usage(): 17 | print("Usage:\n" 18 | "[optional] argv[1] device\n" 19 | "[optional] argv[2] platform\n" 20 | "[optional] argv[3] architecture\n") 21 | 22 | 23 | class BuildRpcServer(object): 24 | EXCHANGE = 'build_servers_exchange' 25 | EXCHANGE_TYPE = 'direct' 26 | 27 | def __init__(self, device, platform, arch): 28 | self.connection_ = None 29 | self.channel_ = None 30 | self.closing_ = False 31 | self.consumer_tag_ = None 32 | self.device_ = device 33 | self.platform_ = platform 34 | self.arch_ = arch 35 | routing_key = gen_routing_key(device, platform, arch) 36 | self.routing_key_ = routing_key 37 | print("Build server for {0} inited, routing_key: {1}!".format(platform, routing_key)) 38 | 39 | def connect(self): 40 | credentials = pika.PlainCredentials(config.USER_NAME, config.PASSWORD) 41 | params = pika.ConnectionParameters(host=config.REMOTE_HOST, credentials=credentials) 42 | return pika.SelectConnection(params, self.on_connection_open, stop_ioloop_on_close=False) 43 | 44 | def reconnect(self): 45 | self.connection_.ioloop.stop() 46 | 47 | if not self.closing_: 48 | self.connection_ = self.connect() 49 | self.connection_.ioloop.start() 50 | 51 | def on_connection_open(self, unused_connection): 52 | self.add_on_connection_close_callback() 53 | self.open_channel() 54 | 55 | def add_on_connection_close_callback(self): 56 | self.connection_.add_on_close_callback(self.on_connection_closed) 57 | 58 | def open_channel(self): 59 | self.connection_.channel(on_open_callback=self.on_channel_open) 60 | 61 | def on_channel_open(self, channel): 62 | self.channel_ = channel 63 | self.add_on_channel_close_callback() 64 | self.setup_exchange(self.EXCHANGE) 65 | 66 | def add_on_channel_close_callback(self): 67 | self.channel_.add_on_close_callback(self.on_channel_closed) 68 | 69 | def setup_exchange(self, exchange_name): 70 | self.channel_.exchange_declare(self.on_exchange_declareok, exchange_name, self.EXCHANGE_TYPE) 71 | 72 | def on_exchange_declareok(self, unused_frame): 73 | self.setup_queue(self.routing_key_) 74 | 75 | def setup_queue(self, queue_name): 76 | print("setup_queue: {0}".format(queue_name)) 77 | self.channel_.queue_declare(self.on_queue_declareok, queue_name) 78 | 79 | def on_queue_declareok(self, method_frame): 80 | self.channel_.queue_bind(self.on_bindok, self.routing_key_, self.EXCHANGE, self.routing_key_) 81 | 82 | def on_bindok(self, unused_frame): 83 | self.start_consuming() 84 | 85 | def start_consuming(self): 86 | self.add_on_cancel_callback() 87 | print("Awaiting RPC build requests") 88 | self.consumer_tag_ = self.channel_.basic_consume(self.on_request, self.routing_key_) 89 | 90 | def on_consumer_cancelled(self, method_frame): 91 | if self.channel_: 92 | self.channel_.close() 93 | 94 | def add_on_cancel_callback(self): 95 | self.channel_.add_on_cancel_callback(self.on_consumer_cancelled) 96 | 97 | def on_channel_closed(self, channel, reply_code, reply_text): 98 | print("on_channel_closed reply_code: {0}, reply_text: {1}".format(reply_code, reply_text)) 99 | self.connection_.close() 100 | 101 | def on_connection_closed(self, connection, reply_code, reply_text): 102 | print("on_connection_closed reply_code: {0}, reply_text: {1}".format(reply_code, reply_text)) 103 | self.channel_ = None 104 | if self.closing_: 105 | self.connection_.ioloop.stop() 106 | else: 107 | self.connection_.add_timeout(5, self.reconnect) 108 | 109 | def run(self): 110 | self.connection_ = self.connect() 111 | self.connection_.ioloop.start() 112 | 113 | def build_package(self, op_id, branding_options, package_types, destination, routing_key): 114 | build_request = build.BuildRequest(self.platform_, self.arch_) 115 | platform = build_request.platform() 116 | arch = platform.architecture() 117 | 118 | platform_and_arch_str = '{0}_{1}'.format(platform.name(), arch.name()) 119 | dir_name = 'build_{0}_for_{1}'.format(platform_and_arch_str, op_id) 120 | 121 | self.send_status(routing_key, op_id, 20.0, 'Building package') 122 | 123 | def store(progress_min, progress_max, routing_key, op_id): 124 | def closure(progress, message): 125 | diff = progress_max - progress_min 126 | perc = round(progress_min + diff * (progress / 100.0), 1) 127 | print('{0}% {1}'.format(perc, message)) 128 | sys.stdout.flush() 129 | self.send_status(routing_key, op_id, perc, message) 130 | 131 | return closure 132 | 133 | store = store(21.0, 79.0, routing_key, op_id) 134 | 135 | saver = build.ProgressSaver(store) 136 | file_paths = build_request.build('..', branding_options, dir_name, None, package_types, saver) 137 | file_path = file_paths[0] 138 | self.send_status(routing_key, op_id, 80.0, 'Loading package to server') 139 | try: 140 | result = config.post_install_step(file_path, destination) 141 | except Exception as ex: 142 | raise ex 143 | 144 | return result 145 | 146 | def send_status(self, routing_key, op_id, progress, status): 147 | json_to_send = {'progress': progress, 'status': status} 148 | properties = pika.BasicProperties(content_type='application/json', correlation_id=op_id, 149 | headers={'type': 'status'}) 150 | if self.channel_: 151 | self.channel_.basic_publish(exchange='', 152 | routing_key=routing_key, 153 | properties=properties, 154 | body=json.dumps(json_to_send)) 155 | 156 | def send_response(self, routing_key, op_id, body): 157 | properties = pika.BasicProperties( 158 | content_type='application/json', 159 | correlation_id=op_id, 160 | headers={'type': 'response'} 161 | ) 162 | if self.channel_: 163 | self.channel_.basic_publish(exchange='', 164 | routing_key=routing_key, 165 | properties=properties, 166 | body=body) 167 | 168 | def on_request(self, ch, method, props, body): 169 | platform_and_arch = '{0}_{1}'.format(self.platform_, self.arch_) 170 | if isinstance(body, bytes): 171 | body = body.decode("utf-8") 172 | 173 | data = json.loads(body) 174 | # self.acknowledge_message(method.delivery_tag) 175 | # return 176 | 177 | branding_variables = data.get('branding_variables') 178 | package_type = data.get('package_type') 179 | destination = data.get('destination') 180 | op_id = props.correlation_id 181 | package_types = [package_type] 182 | 183 | self.send_status(props.reply_to, op_id, 0.0, 'Prepare to build package') 184 | print('Build started for: {0}, platform: {1}'.format(op_id, platform_and_arch)) 185 | try: 186 | response = self.build_package(op_id, shlex.split(branding_variables), package_types, destination, 187 | props.reply_to) 188 | print('Build finished for: {0}, platform: {1}, response: {2}'.format(op_id, platform_and_arch, response)) 189 | json_to_send = {'body': response} 190 | except build_utils.BuildError as ex: 191 | print('Build finished for: {0}, platform: {1}, exception: {2}'.format(op_id, platform_and_arch, str(ex))) 192 | json_to_send = {'error': str(ex)} 193 | except Exception as ex: 194 | print('Build finished for: {0}, platform: {1}, exception: {2}'.format(op_id, platform_and_arch, str(ex))) 195 | json_to_send = {'error': str(ex)} 196 | 197 | self.send_status(props.reply_to, op_id, 100.0, 'Completed') 198 | self.send_response(props.reply_to, op_id, json.dumps(json_to_send)) 199 | self.acknowledge_message(method.delivery_tag) 200 | 201 | def acknowledge_message(self, delivery_tag): 202 | if self.channel_: 203 | self.channel_.basic_ack(delivery_tag) 204 | 205 | 206 | if __name__ == "__main__": 207 | argc = len(sys.argv) 208 | 209 | if argc > 1: 210 | device_str = sys.argv[1] 211 | else: 212 | device_str = 'pc' 213 | 214 | if argc > 2: 215 | platform_str = sys.argv[2] 216 | else: 217 | platform_str = system_info.get_os() 218 | 219 | if argc > 3: 220 | arch_str = sys.argv[3] 221 | else: 222 | arch_str = system_info.get_arch_name() 223 | 224 | server = BuildRpcServer(device_str, platform_str, arch_str) 225 | server.run() 226 | -------------------------------------------------------------------------------- /build/devices/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/build/devices/__init__.py -------------------------------------------------------------------------------- /build/devices/orange_pi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/build/devices/orange_pi/__init__.py -------------------------------------------------------------------------------- /build/devices/orange_pi/hardware/lirc/hardware.conf: -------------------------------------------------------------------------------- 1 | # /etc/lirc/hardware.conf 2 | # 3 | #Chosen Remote Control 4 | REMOTE="None" 5 | REMOTE_MODULES="sunxi_cir" 6 | REMOTE_DRIVER="" 7 | REMOTE_DEVICE="/dev/lirc0" 8 | REMOTE_SOCKET="" 9 | REMOTE_LIRCD_CONF="" 10 | REMOTE_LIRCD_ARGS="" 11 | 12 | #Chosen IR Transmitter 13 | TRANSMITTER="None" 14 | TRANSMITTER_MODULES="sunxi_cir" 15 | TRANSMITTER_DRIVER="" 16 | TRANSMITTER_DEVICE="/dev/lirc0" 17 | TRANSMITTER_SOCKET="" 18 | TRANSMITTER_LIRCD_CONF="" 19 | TRANSMITTER_LIRCD_ARGS="" 20 | 21 | #Disable kernel support. 22 | #Typically, lirc will disable in-kernel support for ir devices in order to 23 | #handle them internally. Set to false to prevent lirc from disabling this 24 | #in-kernel support. 25 | #DISABLE_KERNEL_SUPPORT="true" 26 | 27 | #Enable lircd 28 | START_LIRCD="true" 29 | 30 | #Don't start lircmd even if there seems to be a good config file 31 | #START_LIRCMD="false" 32 | 33 | #Try to load appropriate kernel modules 34 | LOAD_MODULES="true" 35 | 36 | # Default configuration files for your hardware if any 37 | LIRCMD_CONF="" 38 | 39 | #Forcing noninteractive reconfiguration 40 | #If lirc is to be reconfigured by an external application 41 | #that doesn't have a debconf frontend available, the noninteractive 42 | #frontend can be invoked and set to parse REMOTE and TRANSMITTER 43 | #It will then populate all other variables without any user input 44 | #If you would like to configure lirc via standard methods, be sure 45 | #to leave this set to "false" 46 | FORCE_NONINTERACTIVE_RECONFIGURATION="false" 47 | START_LIRCMD="" 48 | -------------------------------------------------------------------------------- /build/devices/orange_pi/orange_pi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import shutil 5 | import subprocess 6 | 7 | from pyfastogt import utils 8 | 9 | LIRC_FOLDER = '/etc/lirc/' 10 | 11 | 12 | def install_orange_pi_h3(): 13 | subprocess.call(['modprobe', 'mali']) 14 | pwd = os.getcwd() 15 | script_dir = os.path.dirname(os.path.realpath(__file__)) 16 | try: 17 | cloned_dir = utils.git_clone('https://github.com/linux-sunxi/sunxi-mali.git') 18 | os.chdir(cloned_dir) 19 | subprocess.call(['make', 'config']) 20 | subprocess.call(['make', 'install']) 21 | os.chdir(pwd) 22 | shutil.rmtree(cloned_dir) 23 | except Exception as ex: 24 | os.chdir(pwd) 25 | raise ex 26 | 27 | try: 28 | cloned_dir = utils.git_clone('https://github.com/fastogt/libvdpau-sunxi.git') 29 | os.chdir(cloned_dir) 30 | subprocess.call(['make', 'install']) 31 | os.chdir(pwd) 32 | shutil.rmtree(cloned_dir) 33 | except Exception as ex: 34 | os.chdir(pwd) 35 | raise ex 36 | 37 | with open('/etc/udev/rules.d/50-mali.rules', 'w') as f: 38 | f.write('KERNEL=="mali", MODE="0660", GROUP="video"\n' 39 | 'KERNEL=="ump", MODE="0660", GROUP="video"') 40 | 41 | with open('/etc/asound.conf', 'w') as f: 42 | f.write('pcm.!default {\n' 43 | 'type hw\n' 44 | 'card 1\n' 45 | '}\n' 46 | 'ctl.!default {\n' 47 | 'type hw\n' 48 | 'card 1\n' 49 | '}') 50 | 51 | standart_egl_path = '/usr/lib/arm-linux-gnueabihf/mesa-egl/' 52 | if os.path.exists(standart_egl_path): 53 | shutil.move(standart_egl_path, '/usr/lib/arm-linux-gnueabihf/.mesa-egl/') 54 | 55 | lirc_conf_path = os.path.join(script_dir, 'hardware/lirc/hardware.conf') 56 | if os.path.exists(LIRC_FOLDER): 57 | dst = os.path.join(LIRC_FOLDER, 'hardware.conf') 58 | shutil.copy(lirc_conf_path, dst) 59 | 60 | 61 | def install_orange_pi_h5(): 62 | script_dir = os.path.dirname(os.path.realpath(__file__)) 63 | 64 | with open('/etc/asound.conf', 'w') as f: 65 | f.write('pcm.!default {\n' 66 | 'type hw\n' 67 | 'card 1\n' 68 | '}\n' 69 | 'ctl.!default {\n' 70 | 'type hw\n' 71 | 'card 1\n' 72 | '}') 73 | 74 | lirc_conf_path = os.path.join(script_dir, 'hardware/lirc/hardware.conf') 75 | if os.path.exists(LIRC_FOLDER): 76 | dst = os.path.join(LIRC_FOLDER, 'hardware.conf') 77 | shutil.copy(lirc_conf_path, dst) 78 | -------------------------------------------------------------------------------- /build/devices/raspberry_pi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/build/devices/raspberry_pi/__init__.py -------------------------------------------------------------------------------- /build/devices/raspberry_pi/raspberry_pi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | 5 | from pyfastogt import utils 6 | 7 | 8 | def install_raspberry_pi(gpu_mem_size: int): 9 | # ln -sf /opt/vc/lib/libEGL.so /usr/lib/arm-linux-gnueabihf/libEGL.so 10 | # ln -sf /opt/vc/lib/libEGL.so /usr/lib/arm-linux-gnueabihf/libEGL.so.1 11 | # ln -sf /opt/vc/lib/libGLESv2.so /usr/lib/arm-linux-gnueabihf/libGLESv2.so 12 | # ln -sf /opt/vc/lib/libGLESv2.so /usr/lib/arm-linux-gnueabihf/libGLESv2.so.2 13 | utils.symlink_force('/opt/vc/lib/libEGL.so', '/usr/lib/arm-linux-gnueabihf/libEGL.so') 14 | utils.symlink_force('/opt/vc/lib/libEGL.so', '/usr/lib/arm-linux-gnueabihf/libEGL.so.1') 15 | utils.symlink_force('/opt/vc/lib/libGLESv2.so', '/usr/lib/arm-linux-gnueabihf/libGLESv2.so') 16 | utils.symlink_force('/opt/vc/lib/libGLESv2.so', '/usr/lib/arm-linux-gnueabihf/libGLESv2.so.2') 17 | 18 | with open("/boot/config.txt", "r+") as f: 19 | line_found = any("gpu_mem" in line for line in f) 20 | if not line_found: 21 | f.seek(0, os.SEEK_END) 22 | f.write("gpu_mem={0}\n".format(gpu_mem_size)) 23 | -------------------------------------------------------------------------------- /build/patch/orange-pi/sdl2/SDL_render_gles2.c.patch: -------------------------------------------------------------------------------- 1 | --- src/render/opengles2/SDL_render_gles2.c 2016-10-20 06:56:26.000000000 +0300 2 | +++ SDL_render_gles2.c 2017-04-03 16:45:27.579283000 +0300 3 | @@ -22,6 +22,8 @@ 4 | 5 | #if SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED 6 | 7 | +typedef char GLchar; 8 | + 9 | #include "SDL_hints.h" 10 | #include "SDL_opengles2.h" 11 | #include "../SDL_sysrender.h" 12 | -------------------------------------------------------------------------------- /images/1024 px_horizontal-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/1024 px_horizontal-01.png -------------------------------------------------------------------------------- /images/128 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/128 px-01.png -------------------------------------------------------------------------------- /images/144 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/144 px-01.png -------------------------------------------------------------------------------- /images/256 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/256 px-01.png -------------------------------------------------------------------------------- /images/256 px_horizontal-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/256 px_horizontal-01.png -------------------------------------------------------------------------------- /images/48 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/48 px-01.png -------------------------------------------------------------------------------- /images/480 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/480 px-01.png -------------------------------------------------------------------------------- /images/480_2 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/480_2 px-01.png -------------------------------------------------------------------------------- /images/512 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/512 px-01.png -------------------------------------------------------------------------------- /images/512 px_horizontal-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/512 px_horizontal-01.png -------------------------------------------------------------------------------- /images/72 px-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/72 px-01.png -------------------------------------------------------------------------------- /images/Horizontal Black-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/Horizontal Black-01.png -------------------------------------------------------------------------------- /images/Horizontal White-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/Horizontal White-01.png -------------------------------------------------------------------------------- /images/Logo Black-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/Logo Black-01.png -------------------------------------------------------------------------------- /images/Logo White-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/Logo White-01.png -------------------------------------------------------------------------------- /images/Logo license.txt: -------------------------------------------------------------------------------- 1 | This logo design created by Dee-y (https://github.com/dee-y) is licensed under a Creative Commons Attribution 4.0 International License (http://creativecommons.org/licenses/by/4.0/) -------------------------------------------------------------------------------- /images/Logotype 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/Logotype 2.png -------------------------------------------------------------------------------- /images/Logotype 2_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/Logotype 2_black.png -------------------------------------------------------------------------------- /images/Logotype 2_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/images/Logotype 2_white.png -------------------------------------------------------------------------------- /install/fastotv/CHANGELOG: -------------------------------------------------------------------------------- 1 | 1.21.1 / January 5, 2019 2 | [Alexandr Topilski] 3 | - Version Bump 4 | 5 | 1.20.0 / December 20, 2019 6 | [Alexandr Topilski] 7 | - Catchups 8 | - Version patch integration 9 | - Private life streams 10 | - New API 1.2.2 11 | - Removed bandwidth check 12 | - Project info for client 13 | - Version Bump 14 | - Send device id 15 | - Change layout 16 | - Text notification 17 | - Protocol update 18 | - Stabilization 19 | - Raspberry PI 20 | - Realtime login password 21 | - Branding 22 | - Gzip compress 23 | - New scripts 24 | - Channels not showing up in list #42 25 | - User state 26 | - Compress messages 27 | - Service notification 28 | - JSON RPC 29 | - Update external libraries 30 | - Fixed deb package for Ubuntu 18 31 | - Https recover 32 | - libpng fix for Linux 33 | - Search channels 34 | - Fix fonts for MacOSX 35 | - Optimize event loop 36 | - Player mode 37 | - Playlist view 38 | - Save dynamic options 39 | - SDL image linkage 40 | - Video info 41 | - EPG basic support 42 | - MacOSX build 43 | - Device info 44 | - Bandwidth estimation 45 | - Enable/Disable audio/video in channel 46 | - Seek stream 47 | - Cuda hwaccel stabilization 48 | - LIRC support 49 | - Added hwaccels: Cuvid, Videotoolbox 50 | - Footer text 51 | - Config file 52 | - Added hwaccels: VDPAU, VAAPI, DXVA2 53 | -------------------------------------------------------------------------------- /install/fastotv/COPYRIGHT: -------------------------------------------------------------------------------- 1 | FastoTV, crossplatform free iptv/stream player. 2 | 3 | Copyright 2018, FastoGT. 4 | 5 | The FastoTV is released under the terms of the GNU General Public 6 | License, version 3. 7 | 8 | The FastoTV Project includes files written by third parties 9 | and used with permission or subject to their respective license 10 | agreements. 11 | 12 | -------------------------------------------------------------------------------- /install/fastotv/android/AndroidManifest.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /install/fastotv/android/configAndroid.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "description": "@CPACK_PACKAGE_DESCRIPTION_SUMMARY@", 3 | "qt": "@_qt5Core_install_prefix@", 4 | "sdk": "@ANDROID_SDK@", 5 | "ndk": "@ANDROID_NDK@", 6 | "toolchain-prefix": "@ANDROID_TOOLCHAIN_MACHINE_NAME@", 7 | "tool-prefix": "@ANDROID_TOOLCHAIN_MACHINE_NAME@", 8 | "toolchain-version": "@ANDROID_COMPILER_VERSION@", 9 | "ndk-host": "@ANDROID_NDK_HOST_SYSTEM_NAME@", 10 | "target-architecture": "@ANDROID_TARGET_ARCH@", 11 | "application-binary": "@CMAKE_INSTALL_PREFIX@/libs/@ANDROID_NDK_ABI_NAME@/lib@PROJECT_NAME@.so", 12 | "android-package-source-directory": "@PACKAGE_SOURCE_ANDROID@/", 13 | "android-package": "net.@PROJECT_NAME_LOWERCASE@" 14 | } 15 | -------------------------------------------------------------------------------- /install/fastotv/android/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/android/icon.png -------------------------------------------------------------------------------- /install/fastotv/android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /install/fastotv/android/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/android/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /install/fastotv/android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /install/fastotv/android/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/android/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /install/fastotv/android/strings.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | @PROJECT_NAME@ 4 | 5 | Can\'t find Ministro service.\nThe application can\'t start. 6 | This application requires Ministro service. Would you like to install it? 7 | Your application encountered a fatal error and cannot continue. 8 | 9 | -------------------------------------------------------------------------------- /install/fastotv/autostart.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | #adduser test1 4 | #mkpasswd --method=md5 5 | #hashed 6 | #Before editing test1:*:16559:0:99999:7::: 7 | #After editing test1:$hashed:16559:0:99999:7::: 8 | 9 | USER_LOGIN=$1 10 | adduser --home /home/$USER_LOGIN/ --force-badname $USER_LOGIN 11 | usermod -a -G video $USER_LOGIN 12 | cp xinitrc /home/$USER_LOGIN/.xinitrc 13 | chown $USER_LOGIN /home/$USER_LOGIN/.xinitrc 14 | 15 | LINE='if [ -z "$DISPLAY" ] && [ -n "$XDG_VTNR" ] && [ "$XDG_VTNR" -eq 1 ]; then exec startx fi' 16 | FILE=/home/$USER_LOGIN/.bashrc 17 | if [ -f "$FILE" ]; then 18 | grep -qF "$LINE" "$FILE" || echo "$LINE" >> "$FILE" 19 | fi 20 | 21 | FILE2=/home/$USER_LOGIN/.bash_profile 22 | if [ -f "$FILE2" ]; then 23 | grep -qF "$LINE" "$FILE2" || echo "$LINE" >> "$FILE2" 24 | fi 25 | -------------------------------------------------------------------------------- /install/fastotv/config.ini.in: -------------------------------------------------------------------------------- 1 | [main_options] 2 | poweroffonexit=@CONFIG_POWER_OFF_ON_EXIT@ 3 | [player_options] 4 | [app_options] 5 | hwaccel=@CONFIG_HWACCEL_METHOD@ 6 | [player_options] 7 | width=@CONFIG_WIDTH@ 8 | height=@CONFIG_HEIGHT@ 9 | -------------------------------------------------------------------------------- /install/fastotv/desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Exec=@PRODUCTNAME@ 4 | Name=@SHORTPRODUCTNAME@ 5 | GenericName=The IDE for redis working. 6 | GenericName[de]=Die IDE der 7 | Icon=@ICONNAME@ 8 | Terminal=false 9 | Categories=Development;IDE;redis; 10 | -------------------------------------------------------------------------------- /install/fastotv/fonts/FreeSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/fonts/FreeSans.ttf -------------------------------------------------------------------------------- /install/fastotv/hardware/lirc/lircrc.conf.in: -------------------------------------------------------------------------------- 1 | begin 2 | prog = @PROJECT_NAME_LOWERCASE@ 3 | button = KEY_OK 4 | config = LIRC_KEY_OK 5 | end 6 | 7 | begin 8 | prog = @PROJECT_NAME_LOWERCASE@ 9 | button = KEY_LEFT 10 | config = LIRC_KEY_LEFT 11 | end 12 | 13 | begin 14 | prog = @PROJECT_NAME_LOWERCASE@ 15 | button = KEY_UP 16 | config = LIRC_KEY_UP 17 | end 18 | 19 | begin 20 | prog = @PROJECT_NAME_LOWERCASE@ 21 | button = KEY_RIGHT 22 | config = LIRC_KEY_RIGHT 23 | end 24 | 25 | begin 26 | prog = @PROJECT_NAME_LOWERCASE@ 27 | button = KEY_DOWN 28 | config = LIRC_KEY_DOWN 29 | end 30 | 31 | begin 32 | prog = @PROJECT_NAME_LOWERCASE@ 33 | button = KEY_EXIT 34 | config = LIRC_KEY_EXIT 35 | end 36 | 37 | begin 38 | prog = @PROJECT_NAME_LOWERCASE@ 39 | button = KEY_MUTE 40 | config = LIRC_KEY_MUTE 41 | end 42 | -------------------------------------------------------------------------------- /install/fastotv/linux/gentoo.ebuild.in: -------------------------------------------------------------------------------- 1 | # Copyright 1999-2013 Gentoo Foundation 2 | # Distributed under the terms of the GNU General Public License v3 3 | # $Header: $ 4 | 5 | EAPI="6" 6 | 7 | inherit multilib unpacker 8 | 9 | DESCRIPTION="@PROJECT_DESCRIPTION@" 10 | HOMEPAGE="@PROJECT_DOMAIN@" 11 | SRC_URI="@PROJECT_DOWNLOAD_LINK@/@CPACK_PACKAGE_FILE_NAME@.deb" 12 | 13 | LICENSE="GPL-v3" 14 | SLOT="0" 15 | KEYWORDS="~amd64 ~x86" 16 | IUSE="" 17 | 18 | RDEPEND=">=sys-libs/libstdc++-v3-3.3.6-r1" 19 | DEPEND="${RDEPEND} 20 | >=dev-qt/qtcore-5.4.0:5 21 | >=dev-qt/qtgui-5.4.0:5 22 | >=dev-qt/qtwebkit-5.4.0:5" 23 | 24 | ##S=${WORKDIR}/${P}.0 25 | S=${WORKDIR} 26 | 27 | #RESTRICT="strip" 28 | 29 | src_install() { 30 | sed -i '3s|Exec=@PROJECT_NAME_LOWERCASE@|Exec=@PROJECT_NAME_LOWERCASE@.sh|g' "${S}/opt/@PROJECT_NAME_LOWERCASE@/share/applications/@PROJECT_NAME_LOWERCASE@.desktop" || die 31 | sed -i '7s|Icon=@PROJECT_NAME_LOWERCASE@.png|Icon=@PROJECT_NAME_LOWERCASE@|g' "${S}/opt/@PROJECT_NAME_LOWERCASE@/share/applications/@PROJECT_NAME_LOWERCASE@.desktop" || die 32 | sed -i '9s|IDE;redis;|IDE;|g' "${S}/opt/@PROJECT_NAME_LOWERCASE@/share/applications/@PROJECT_NAME_LOWERCASE@.desktop" || die 33 | 34 | dodir /usr/{bin,share} 35 | mv "${S}"/opt/@PROJECT_NAME_LOWERCASE@/{bin,share} "${D}"/usr/ 36 | 37 | cp -pPR "${WORKDIR}"/* "${D}"/ || die "copying files failed!" 38 | } 39 | -------------------------------------------------------------------------------- /install/fastotv/linux/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/linux/icon.png -------------------------------------------------------------------------------- /install/fastotv/linux/postinst.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | ln -sf @CPACK_PACKAGING_INSTALL_PREFIX@/@TARGET_INSTALL_DESTINATION@/@PROJECT_NAME_LOWERCASE@ @EXECUTABLE_PATH@ 4 | chmod +x @EXECUTABLE_PATH@ 5 | cp @CPACK_PACKAGING_INSTALL_PREFIX@/@SHARE_INSTALL_DESTINATION@/applications/@PROJECT_NAME_LOWERCASE@.desktop /usr/share/applications/@PROJECT_NAME_LOWERCASE@.desktop 6 | cp @CPACK_PACKAGING_INSTALL_PREFIX@/@SHARE_INSTALL_DESTINATION@/icons/@PROJECT_NAME_LOWERCASE@.png /usr/share/icons/@PROJECT_NAME_LOWERCASE@.png 7 | -------------------------------------------------------------------------------- /install/fastotv/linux/prerm.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if test -e @EXECUTABLE_PATH@ ; then 5 | rm @EXECUTABLE_PATH@ 6 | fi 7 | 8 | if test -e /usr/share/applications/@PROJECT_NAME_LOWERCASE@.desktop ; then 9 | rm /usr/share/applications/@PROJECT_NAME_LOWERCASE@.desktop 10 | fi 11 | 12 | if test -e /usr/share/icons/@PROJECT_NAME_LOWERCASE@.png ; then 13 | rm /usr/share/icons/@PROJECT_NAME_LOWERCASE@.png 14 | fi 15 | -------------------------------------------------------------------------------- /install/fastotv/linux/xinitrc.in: -------------------------------------------------------------------------------- 1 | # Please add next line into ~/.bash_profile or ~/.bashrc according system 2 | #if [ -z "$DISPLAY" ] && [ -n "$XDG_VTNR" ] && [ "$XDG_VTNR" -eq 1 ]; then 3 | # exec startx 4 | #fi 5 | 6 | exec @EXECUTABLE_PATH@ -------------------------------------------------------------------------------- /install/fastotv/macosx/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/macosx/icon.icns -------------------------------------------------------------------------------- /install/fastotv/resources/connection_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/resources/connection_error.png -------------------------------------------------------------------------------- /install/fastotv/resources/down_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/resources/down_arrow.png -------------------------------------------------------------------------------- /install/fastotv/resources/left_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/resources/left_arrow.png -------------------------------------------------------------------------------- /install/fastotv/resources/offline_channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/resources/offline_channel.png -------------------------------------------------------------------------------- /install/fastotv/resources/right_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/resources/right_arrow.png -------------------------------------------------------------------------------- /install/fastotv/resources/unknown_channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/resources/unknown_channel.png -------------------------------------------------------------------------------- /install/fastotv/resources/up_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/resources/up_arrow.png -------------------------------------------------------------------------------- /install/fastotv/windows/database.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/windows/database.bmp -------------------------------------------------------------------------------- /install/fastotv/windows/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/windows/icon.ico -------------------------------------------------------------------------------- /install/fastotv/windows/nsis-top-logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastogt/fastotv/bf17ee9ac75b30645f6494e7c3df596b6a188ad9/install/fastotv/windows/nsis-top-logo.bmp -------------------------------------------------------------------------------- /install/fastotv/windows/winres.rc.in: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON "@ICON_FILE@" 2 | 3 | #define VOS_NT_WINDOWS32 0x00040004L 4 | #define VFT_APP 0x00000001L 5 | 6 | #define VER_FILEVERSION @MAJOR_VER@,@MINOR_VER1@,@MINOR_VER2@,0 7 | #define VER_FILEVERSION_STR "@MAJOR_VER@.@MINOR_VER1@.@MINOR_VER2@\0" 8 | 9 | #define VER_PRODUCTVERSION @MAJOR_VER@,@MINOR_VER1@,@MINOR_VER2@,0 10 | #define VER_PRODUCTVERSION_STR "@MAJOR_VER@.@MINOR_VER1@.@MINOR_VER2@\0" 11 | 12 | 1 VERSIONINFO 13 | FILEVERSION VER_FILEVERSION 14 | PRODUCTVERSION VER_PRODUCTVERSION 15 | FILEFLAGSMASK 0x3fL 16 | #ifdef _DEBUG 17 | FILEFLAGS 0x1L 18 | #else 19 | FILEFLAGS 0x0L 20 | #endif 21 | FILEOS VOS_NT_WINDOWS32 22 | FILETYPE VFT_APP 23 | FILESUBTYPE 0x0L 24 | BEGIN 25 | BLOCK "StringFileInfo" 26 | BEGIN 27 | BLOCK "040904e4" 28 | BEGIN 29 | VALUE "CompanyName", "@COMPANYNAME@\0" 30 | VALUE "FileDescription", "@PRODUCTNAME@\0" 31 | VALUE "FileVersion", VER_FILEVERSION_STR 32 | VALUE "LegalCopyright", "@PRODUCTCOPYRIGHT@\0" 33 | VALUE "ProductName", "@PRODUCTNAME@\0" 34 | VALUE "ProductVersion", VER_PRODUCTVERSION_STR 35 | VALUE "OriginalFilename", "@SHORTPRODUCTNAME@.exe\0" 36 | VALUE "InternalName", "@SHORTPRODUCTNAME@\0" 37 | END 38 | END 39 | BLOCK "VarFileInfo" 40 | BEGIN 41 | /* The following line should only be modified for localized versions. */ 42 | /* It consists of any number of WORD,WORD pairs, with each pair */ 43 | /* describing a language,codepage combination supported by the file. */ 44 | /* */ 45 | /* For example, a file might have values "0x409,1252" indicating that it */ 46 | /* supports English language (0x409) in the Windows ANSI codepage (1252). */ 47 | 48 | VALUE "Translation", 0x409, 1252 49 | END 50 | END 51 | -------------------------------------------------------------------------------- /scripts/create_pre_commit_hook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | HOOKS="pre-commit" 4 | ROOT_DIR=$(git rev-parse --show-toplevel) 5 | 6 | for hook in $HOOKS; do 7 | if [ ! -f $ROOT_DIR/.git/hooks/$hook ]; then 8 | ln -s $ROOT_DIR/scripts/$hook $ROOT_DIR/.git/hooks/$hook 9 | fi 10 | done 11 | 12 | -------------------------------------------------------------------------------- /scripts/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | TOTAL_ERRORS=0 4 | 5 | for file in `git diff-index --name-only --diff-filter=d HEAD`; do 6 | case "${file#*.}" in 7 | cpp|c|h) 8 | clang-format -i "${file}" 9 | cpplint "${file}" 10 | TOTAL_ERRORS=$(expr $TOTAL_ERRORS + $?); 11 | ;; 12 | esac 13 | done 14 | 15 | exit $TOTAL_ERRORS 16 | -------------------------------------------------------------------------------- /src/client/cmdutils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include // for PRIx64 22 | #include // for snprintf 23 | #include // for string 24 | 25 | #include // for CONFIG_AVDEVICE 26 | 27 | extern "C" { 28 | #include // for av_get_media_type_string 29 | #include // for av_get_channel_layout_string 30 | #include // for AVDictionary 31 | #include // for av_get_pix_fmt_name 32 | #include // for av_get_sample_fmt_name 33 | } 34 | 35 | #include // for ConvertFromString 36 | #include // for COMPACT_LOG_WARNING, WARNING_LOG 37 | #include // for DISALLOW_COPY_AND_ASSIGN 38 | 39 | void show_license(); 40 | void show_version(); 41 | void show_help_tv_player(const std::string& topic); 42 | void show_help_player(const std::string& topic); 43 | void show_buildconf(); 44 | void show_formats(); 45 | void show_devices(); 46 | void show_muxers(); 47 | void show_demuxers(); 48 | void show_codecs(); 49 | void show_hwaccels(); 50 | void show_decoders(); 51 | void show_encoders(); 52 | void show_bsfs(); 53 | void show_protocols(); 54 | void show_filters(); 55 | void show_pix_fmts(); 56 | void show_layouts(); 57 | void show_sample_fmts(); 58 | void show_colors(); 59 | 60 | #if CONFIG_AVDEVICE 61 | void show_sinks(const std::string& device); 62 | void show_sources(const std::string& device); 63 | #endif 64 | 65 | bool parse_bool(const std::string& bool_str, bool* result); 66 | 67 | template 68 | bool parse_number(const std::string& number_str, T min, T max, T* result) { 69 | if (number_str.empty() || !result) { 70 | WARNING_LOG() << "Can't parse value(number) invalid arguments!"; 71 | return false; 72 | } 73 | 74 | T lresult; 75 | if (!common::ConvertFromString(number_str, &lresult)) { 76 | WARNING_LOG() << "Can't parse value(number) value: " << number_str; 77 | return false; 78 | } 79 | 80 | if (lresult < min || lresult > max) { 81 | WARNING_LOG() << "The value for " << number_str << " was " << lresult << " which is not within " << min << " - " 82 | << max; 83 | return false; 84 | } 85 | 86 | *result = lresult; 87 | return true; 88 | } 89 | 90 | #define media_type_string av_get_media_type_string 91 | 92 | #define GET_PIX_FMT_NAME(pix_fmt) const char* name = av_get_pix_fmt_name(pix_fmt); 93 | 94 | #define GET_SAMPLE_FMT_NAME(sample_fmt) const char* name = av_get_sample_fmt_name(sample_fmt) 95 | 96 | #define GET_SAMPLE_RATE_NAME(rate) \ 97 | char name[16]; \ 98 | snprintf(name, sizeof(name), "%d", rate); 99 | 100 | #define GET_CH_LAYOUT_NAME(ch_layout) \ 101 | char name[16]; \ 102 | snprintf(name, sizeof(name), "0x%" PRIx64, ch_layout); 103 | 104 | #define GET_CH_LAYOUT_DESC(ch_layout) \ 105 | char name[128]; \ 106 | av_get_channel_layout_string(name, sizeof(name), 0, ch_layout); 107 | -------------------------------------------------------------------------------- /src/client/events/network_events.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/events/network_events.h" 20 | 21 | namespace fastotv { 22 | namespace client { 23 | namespace events { 24 | 25 | ConnectInfo::ConnectInfo() {} 26 | 27 | ConnectInfo::ConnectInfo(const common::net::HostAndPort& host) : host(host) {} 28 | 29 | } // namespace events 30 | } // namespace client 31 | } // namespace fastotv 32 | -------------------------------------------------------------------------------- /src/client/events/network_events.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include // for HostAndPort 22 | 23 | #include // for EventBase, EventsType::C... 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define CLIENT_DISCONNECT_EVENT static_cast(USER_EVENTS + 1) 34 | #define CLIENT_CONNECT_EVENT static_cast(USER_EVENTS + 2) 35 | #define CLIENT_AUTHORIZED_EVENT static_cast(USER_EVENTS + 3) 36 | #define CLIENT_UNAUTHORIZED_EVENT static_cast(USER_EVENTS + 4) 37 | #define CLIENT_SERVER_INFO_EVENT static_cast(USER_EVENTS + 5) 38 | #define CLIENT_CONFIG_CHANGE_EVENT static_cast(USER_EVENTS + 6) 39 | #define CLIENT_RECEIVE_CHANNELS_EVENT static_cast(USER_EVENTS + 7) 40 | #define CLIENT_RECEIVE_RUNTIME_CHANNELS_EVENT static_cast(USER_EVENTS + 8) 41 | #define CLIENT_CHAT_MESSAGE_SENT_EVENT static_cast(USER_EVENTS + 9) 42 | #define CLIENT_CHAT_MESSAGE_RECEIVE_EVENT static_cast(USER_EVENTS + 10) 43 | #define CLIENT_NOTIFICATION_TEXT_EVENT static_cast(USER_EVENTS + 11) 44 | #define CLIENT_NOTIFICATION_SHUTDOWN_EVENT static_cast(USER_EVENTS + 12) 45 | 46 | namespace fastotv { 47 | namespace client { 48 | namespace events { 49 | 50 | class TvConfig {}; 51 | 52 | struct ConnectInfo { 53 | ConnectInfo(); 54 | explicit ConnectInfo(const common::net::HostAndPort& host); 55 | 56 | common::net::HostAndPort host; 57 | }; 58 | 59 | struct ChannelsMixInfo { 60 | commands_info::ChannelsInfo channels; 61 | commands_info::VodsInfo vods; 62 | commands_info::ChannelsInfo private_channels; 63 | }; 64 | 65 | typedef fastoplayer::gui::events::EventBase ClientDisconnectedEvent; 66 | typedef fastoplayer::gui::events::EventBase ClientConnectedEvent; 67 | typedef fastoplayer::gui::events::EventBase ClientAuthorizedEvent; 68 | typedef fastoplayer::gui::events::EventBase ClientUnAuthorizedEvent; 69 | typedef fastoplayer::gui::events::EventBase ClientServerInfoEvent; 70 | typedef fastoplayer::gui::events::EventBase ClientConfigChangeEvent; 71 | typedef fastoplayer::gui::events::EventBase ReceiveChannelsEvent; 72 | typedef fastoplayer::gui::events::EventBase 73 | ReceiveRuntimeChannelEvent; 74 | typedef fastoplayer::gui::events::EventBase 75 | NotificationTextEvent; 76 | typedef fastoplayer::gui::events::EventBase 77 | NotificationShutdownEvent; 78 | 79 | } // namespace events 80 | } // namespace client 81 | } // namespace fastotv 82 | -------------------------------------------------------------------------------- /src/client/inner/inner_tcp_handler.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/inner/inner_tcp_handler.h" 20 | 21 | #include 22 | #include 23 | 24 | #include // for fApp 25 | #include // for IoLoop 26 | #include // for connect 27 | 28 | #include "client/events/network_events.h" // for BandwidtInfo, Con... 29 | 30 | #include 31 | #include 32 | #include // for ChannelsInfo 33 | #include // for ServerInfo 34 | #include 35 | 36 | #define CHANNELS_ARRAY_FIELD "channels" 37 | #define VODS_ARRAY_FIELD "vods" 38 | #define PRIVATE_CHANNELS_ARRAY_FIELD "private_channels" 39 | 40 | namespace fastotv { 41 | namespace client { 42 | namespace inner { 43 | 44 | InnerTcpHandler::InnerTcpHandler(const common::net::HostAndPort& server_host, const commands_info::AuthInfo& auth_info) 45 | : common::libev::IoLoopObserver(), 46 | inner_connection_(nullptr), 47 | ping_server_id_timer_(INVALID_TIMER_ID), 48 | server_host_(server_host), 49 | auth_info_(auth_info) {} 50 | 51 | InnerTcpHandler::~InnerTcpHandler() { 52 | CHECK(!inner_connection_); 53 | } 54 | 55 | void InnerTcpHandler::PreLooped(common::libev::IoLoop* server) { 56 | ping_server_id_timer_ = server->CreateTimer(ping_timeout_server, true); 57 | 58 | Connect(server); 59 | } 60 | 61 | void InnerTcpHandler::Accepted(common::libev::IoClient* client) { 62 | UNUSED(client); 63 | } 64 | 65 | void InnerTcpHandler::Moved(common::libev::IoLoop* server, common::libev::IoClient* client) { 66 | UNUSED(server); 67 | UNUSED(client); 68 | } 69 | 70 | void InnerTcpHandler::Closed(common::libev::IoClient* client) { 71 | if (client == inner_connection_) { 72 | Client* iclient = static_cast(client); 73 | common::net::socket_info info = iclient->GetInfo(); 74 | common::net::HostAndPort host(info.host(), info.port()); 75 | events::ConnectInfo cinf(host); 76 | fApp->PostEvent(new events::ClientDisconnectedEvent(this, cinf)); 77 | inner_connection_ = nullptr; 78 | return; 79 | } 80 | } 81 | 82 | void InnerTcpHandler::DataReceived(common::libev::IoClient* client) { 83 | if (client == inner_connection_) { 84 | std::string buff; 85 | Client* iclient = static_cast(client); 86 | common::ErrnoError err = iclient->ReadCommand(&buff); 87 | if (err) { 88 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 89 | ignore_result(client->Close()); 90 | delete client; 91 | return; 92 | } 93 | 94 | HandleInnerDataReceived(iclient, buff); 95 | } 96 | } 97 | 98 | void InnerTcpHandler::DataReadyToWrite(common::libev::IoClient* client) { 99 | UNUSED(client); 100 | } 101 | 102 | void InnerTcpHandler::PostLooped(common::libev::IoLoop* server) { 103 | UNUSED(server); 104 | if (ping_server_id_timer_ != INVALID_TIMER_ID) { 105 | server->RemoveTimer(ping_server_id_timer_); 106 | ping_server_id_timer_ = INVALID_TIMER_ID; 107 | } 108 | 109 | CHECK(!inner_connection_); 110 | } 111 | 112 | void InnerTcpHandler::TimerEmited(common::libev::IoLoop* server, common::libev::timer_id_t id) { 113 | UNUSED(server); 114 | if (id == ping_server_id_timer_ && inner_connection_) { 115 | Client* client = inner_connection_; 116 | common::ErrnoError err = client->Ping(); 117 | if (err) { 118 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 119 | ignore_result(client->Close()); 120 | delete client; 121 | } 122 | } 123 | } 124 | 125 | void InnerTcpHandler::Accepted(common::libev::IoChild* child) { 126 | UNUSED(child); 127 | } 128 | 129 | void InnerTcpHandler::Moved(common::libev::IoLoop* server, common::libev::IoChild* child) { 130 | UNUSED(server); 131 | UNUSED(child); 132 | } 133 | 134 | void InnerTcpHandler::ChildStatusChanged(common::libev::IoChild* child, int status, int signal) { 135 | UNUSED(child); 136 | UNUSED(status); 137 | UNUSED(signal); 138 | } 139 | 140 | void InnerTcpHandler::ActivateRequest() { 141 | if (!inner_connection_) { 142 | return; 143 | } 144 | 145 | Client* client = inner_connection_; 146 | common::ErrnoError err = client->Login(auth_info_); 147 | if (err) { 148 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 149 | ignore_result(client->Close()); 150 | delete client; 151 | } 152 | } 153 | 154 | void InnerTcpHandler::RequestServerInfo() { 155 | if (!inner_connection_) { 156 | return; 157 | } 158 | 159 | Client* client = inner_connection_; 160 | common::ErrnoError err = client->GetServerInfo(); 161 | if (err) { 162 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 163 | ignore_result(client->Close()); 164 | delete client; 165 | } 166 | } 167 | 168 | void InnerTcpHandler::RequestChannels() { 169 | if (!inner_connection_) { 170 | return; 171 | } 172 | 173 | Client* client = inner_connection_; 174 | common::ErrnoError err = client->GetChannels(); 175 | if (err) { 176 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 177 | ignore_result(client->Close()); 178 | delete client; 179 | } 180 | } 181 | 182 | void InnerTcpHandler::RequesRuntimeChannelInfo(stream_id_t sid) { 183 | if (!inner_connection_) { 184 | return; 185 | } 186 | 187 | Client* client = inner_connection_; 188 | common::ErrnoError err = client->GetRuntimeChannelInfo(sid); 189 | if (err) { 190 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 191 | ignore_result(client->Close()); 192 | delete client; 193 | } 194 | } 195 | 196 | void InnerTcpHandler::Connect(common::libev::IoLoop* server) { 197 | if (!server) { 198 | return; 199 | } 200 | 201 | DisConnect(common::make_error("Reconnect")); 202 | 203 | common::net::socket_info client_info; 204 | common::ErrnoError err = common::net::connect(server_host_, common::net::ST_SOCK_STREAM, nullptr, &client_info); 205 | if (err) { 206 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 207 | events::ConnectInfo cinf(server_host_); 208 | auto ex_event = 209 | common::make_exception_event(new events::ClientConnectedEvent(this, cinf), common::make_error_from_errno(err)); 210 | fApp->PostEvent(ex_event); 211 | return; 212 | } 213 | 214 | Client* connection = new Client(server, client_info); 215 | inner_connection_ = connection; 216 | if (server->RegisterClient(connection)) { 217 | events::ConnectInfo cinf(server_host_); 218 | fApp->PostEvent(new events::ClientConnectedEvent(this, cinf)); 219 | } 220 | } 221 | 222 | void InnerTcpHandler::DisConnect(common::Error err) { 223 | UNUSED(err); 224 | if (inner_connection_) { 225 | Client* connection = inner_connection_; 226 | ignore_result(connection->Close()); 227 | delete connection; 228 | } 229 | } 230 | 231 | common::ErrnoError InnerTcpHandler::HandleRequestServerPing(Client* client, const protocol::request_t* req) { 232 | if (req->params) { 233 | const char* params_ptr = req->params->c_str(); 234 | json_object* jstop = json_tokener_parse(params_ptr); 235 | if (!jstop) { 236 | return common::make_errno_error_inval(); 237 | } 238 | 239 | common::daemon::commands::ServerPingInfo server_ping_info; 240 | common::Error err_des = server_ping_info.DeSerialize(jstop); 241 | json_object_put(jstop); 242 | if (err_des) { 243 | const std::string err_str = err_des->GetDescription(); 244 | return common::make_errno_error(err_str, EAGAIN); 245 | } 246 | 247 | return client->Pong(req->id); 248 | } 249 | 250 | return common::make_errno_error_inval(); 251 | } 252 | 253 | common::ErrnoError InnerTcpHandler::HandleRequestServerClientInfo(Client* client, const protocol::request_t* req) { 254 | return client->SystemInfo(req->id, auth_info_.GetLogin(), auth_info_.GetDeviceID(), 255 | commands_info::ProjectInfo(PROJECT_NAME_LOWERCASE, PROJECT_VERSION)); 256 | } 257 | 258 | common::ErrnoError InnerTcpHandler::HandleRequestServerTextNotification(Client* client, 259 | const protocol::request_t* req) { 260 | if (req->params) { 261 | const char* params_ptr = req->params->c_str(); 262 | json_object* jnotify_text = json_tokener_parse(params_ptr); 263 | if (!jnotify_text) { 264 | return common::make_errno_error_inval(); 265 | } 266 | 267 | commands_info::NotificationTextInfo notification_text_info; 268 | common::Error err_des = notification_text_info.DeSerialize(jnotify_text); 269 | json_object_put(jnotify_text); 270 | if (err_des) { 271 | const std::string err_str = err_des->GetDescription(); 272 | return common::make_errno_error(err_str, EAGAIN); 273 | } 274 | 275 | fApp->PostEvent(new events::NotificationTextEvent(this, notification_text_info)); 276 | return client->NotificationTextOK(req->id); 277 | } 278 | 279 | return common::make_errno_error_inval(); 280 | } 281 | 282 | common::ErrnoError InnerTcpHandler::HandleRequestServerShutdownNotification(Client* client, const protocol::request_t* req) { 283 | if (req->params) { 284 | const char* params_ptr = req->params->c_str(); 285 | json_object* jnotify_text = json_tokener_parse(params_ptr); 286 | if (!jnotify_text) { 287 | return common::make_errno_error_inval(); 288 | } 289 | 290 | commands_info::ShutDownInfo shutdown_info; 291 | common::Error err_des = shutdown_info.DeSerialize(jnotify_text); 292 | json_object_put(jnotify_text); 293 | if (err_des) { 294 | const std::string err_str = err_des->GetDescription(); 295 | return common::make_errno_error(err_str, EAGAIN); 296 | } 297 | 298 | fApp->PostEvent(new events::NotificationShutdownEvent(this, shutdown_info)); 299 | return client->NotificationTextOK(req->id); 300 | } 301 | 302 | return common::make_errno_error_inval(); 303 | } 304 | 305 | common::ErrnoError InnerTcpHandler::HandleInnerDataReceived(Client* client, const std::string& input_command) { 306 | protocol::request_t* req = nullptr; 307 | protocol::response_t* resp = nullptr; 308 | common::Error err_parse = common::protocols::json_rpc::ParseJsonRPC(input_command, &req, &resp); 309 | if (err_parse) { 310 | const std::string err_str = err_parse->GetDescription(); 311 | return common::make_errno_error(err_str, EAGAIN); 312 | } 313 | 314 | if (req) { 315 | DEBUG_LOG() << "Received request: " << input_command; 316 | common::ErrnoError err = HandleRequestCommand(client, req); 317 | if (err) { 318 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 319 | } 320 | delete req; 321 | } else if (resp) { 322 | DEBUG_LOG() << "Received responce: " << input_command; 323 | common::ErrnoError err = HandleResponceCommand(client, resp); 324 | if (err) { 325 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 326 | } 327 | delete resp; 328 | } else { 329 | DNOTREACHED(); 330 | return common::make_errno_error("Invalid command type.", EINVAL); 331 | } 332 | 333 | return common::ErrnoError(); 334 | } 335 | 336 | common::ErrnoError InnerTcpHandler::HandleRequestCommand(Client* client, const protocol::request_t* req) { 337 | Client* sclient = static_cast(client); 338 | if (req->method == SERVER_PING) { 339 | return HandleRequestServerPing(sclient, req); 340 | } else if (req->method == SERVER_GET_CLIENT_INFO) { 341 | return HandleRequestServerClientInfo(sclient, req); 342 | } else if (req->method == SERVER_TEXT_NOTIFICATION) { 343 | return HandleRequestServerTextNotification(sclient, req); 344 | } else if (req->method == SERVER_SHUTDOWN_NOTIFICATION) { 345 | return HandleRequestServerShutdownNotification(sclient, req); 346 | } 347 | 348 | WARNING_LOG() << "Received unknown command: " << req->method; 349 | return common::ErrnoError(); 350 | } 351 | 352 | common::ErrnoError InnerTcpHandler::HandleResponceClientActivateDevice(Client* client, 353 | const protocol::response_t* resp) { 354 | UNUSED(client); 355 | if (resp->IsMessage()) { 356 | return common::ErrnoError(); 357 | } 358 | return common::ErrnoError(); 359 | } 360 | 361 | common::ErrnoError InnerTcpHandler::HandleResponceClientLogin(Client* client, const protocol::response_t* resp) { 362 | if (resp->IsMessage()) { 363 | client->SetName(auth_info_.GetLogin()); 364 | fApp->PostEvent(new events::ClientAuthorizedEvent(this, auth_info_)); 365 | return common::ErrnoError(); 366 | } 367 | 368 | common::Error err = common::make_error(resp->error->message); 369 | auto ex_event = common::make_exception_event(new events::ClientAuthorizedEvent(this, auth_info_), err); 370 | fApp->PostEvent(ex_event); 371 | return common::ErrnoError(); 372 | } 373 | 374 | common::ErrnoError InnerTcpHandler::HandleResponceClientPing(Client* client, const protocol::response_t* resp) { 375 | UNUSED(client); 376 | if (resp->IsMessage()) { 377 | const char* params_ptr = resp->message->result.c_str(); 378 | json_object* jserver_ping = json_tokener_parse(params_ptr); 379 | if (!jserver_ping) { 380 | return common::make_errno_error_inval(); 381 | } 382 | 383 | common::daemon::commands::ServerPingInfo server_ping_info; 384 | common::Error err_des = server_ping_info.DeSerialize(jserver_ping); 385 | json_object_put(jserver_ping); 386 | if (err_des) { 387 | const std::string err_str = err_des->GetDescription(); 388 | return common::make_errno_error(err_str, EAGAIN); 389 | } 390 | return common::ErrnoError(); 391 | } 392 | return common::ErrnoError(); 393 | } 394 | 395 | common::ErrnoError InnerTcpHandler::HandleResponceClientGetServerInfo(Client* client, 396 | const protocol::response_t* resp) { 397 | UNUSED(client); 398 | 399 | if (resp->IsMessage()) { 400 | const char* params_ptr = resp->message->result.c_str(); 401 | json_object* jserver_info = json_tokener_parse(params_ptr); 402 | if (!jserver_info) { 403 | return common::make_errno_error_inval(); 404 | } 405 | 406 | commands_info::ServerInfo sinf; 407 | common::Error err_des = sinf.DeSerialize(jserver_info); 408 | json_object_put(jserver_info); 409 | if (err_des) { 410 | const std::string err_str = err_des->GetDescription(); 411 | return common::make_errno_error(err_str, EAGAIN); 412 | } 413 | 414 | fApp->PostEvent(new events::ClientServerInfoEvent(this, sinf)); 415 | return common::ErrnoError(); 416 | } 417 | 418 | common::Error err = common::make_error(resp->error->message); 419 | auto ex_event = 420 | common::make_exception_event(new events::ClientServerInfoEvent(this, commands_info::ServerInfo()), err); 421 | fApp->PostEvent(ex_event); 422 | return common::ErrnoError(); 423 | } 424 | 425 | common::ErrnoError InnerTcpHandler::HandleResponceClientGetChannels(Client* client, const protocol::response_t* resp) { 426 | UNUSED(client); 427 | if (resp->IsMessage()) { 428 | const char* params_ptr = resp->message->result.c_str(); 429 | json_object* jchannels_info = json_tokener_parse(params_ptr); 430 | if (!jchannels_info) { 431 | return common::make_errno_error_inval(); 432 | } 433 | 434 | json_object* jchannels_array = nullptr; 435 | json_bool jchannels_array_exists = 436 | json_object_object_get_ex(jchannels_info, CHANNELS_ARRAY_FIELD, &jchannels_array); 437 | if (!jchannels_array_exists) { 438 | json_object_put(jchannels_info); 439 | return common::make_errno_error_inval(); 440 | } 441 | 442 | json_object* jvods_array = nullptr; 443 | json_bool vods_array_exists = json_object_object_get_ex(jchannels_info, VODS_ARRAY_FIELD, &jvods_array); 444 | if (!vods_array_exists) { 445 | json_object_put(jchannels_info); 446 | return common::make_errno_error_inval(); 447 | } 448 | 449 | json_object* jprivate_channels_array = nullptr; 450 | json_bool jprivate_channels_array_exists = 451 | json_object_object_get_ex(jchannels_info, PRIVATE_CHANNELS_ARRAY_FIELD, &jprivate_channels_array); 452 | if (!jprivate_channels_array_exists) { 453 | json_object_put(jchannels_info); 454 | return common::make_errno_error_inval(); 455 | } 456 | 457 | commands_info::ChannelsInfo channels; 458 | common::Error err_des = channels.DeSerialize(jchannels_array); 459 | if (err_des) { 460 | json_object_put(jchannels_info); 461 | const std::string err_str = err_des->GetDescription(); 462 | return common::make_errno_error(err_str, EAGAIN); 463 | } 464 | 465 | commands_info::VodsInfo vods; 466 | err_des = vods.DeSerialize(jvods_array); 467 | if (err_des) { 468 | json_object_put(jchannels_info); 469 | const std::string err_str = err_des->GetDescription(); 470 | return common::make_errno_error(err_str, EAGAIN); 471 | } 472 | 473 | commands_info::ChannelsInfo private_channels; 474 | err_des = private_channels.DeSerialize(jprivate_channels_array); 475 | if (err_des) { 476 | json_object_put(jchannels_info); 477 | const std::string err_str = err_des->GetDescription(); 478 | return common::make_errno_error(err_str, EAGAIN); 479 | } 480 | 481 | json_object_put(jchannels_info); 482 | events::ChannelsMixInfo ch = {channels, vods, private_channels}; 483 | fApp->PostEvent(new events::ReceiveChannelsEvent(this, ch)); 484 | return common::ErrnoError(); 485 | } 486 | return common::ErrnoError(); 487 | } 488 | 489 | common::ErrnoError InnerTcpHandler::HandleResponceClientGetruntimeChannelInfo(Client* client, 490 | const protocol::response_t* resp) { 491 | UNUSED(client); 492 | if (resp->IsMessage()) { 493 | const char* params_ptr = resp->message->result.c_str(); 494 | json_object* jchannels_info = json_tokener_parse(params_ptr); 495 | if (!jchannels_info) { 496 | return common::make_errno_error_inval(); 497 | } 498 | 499 | commands_info::RuntimeChannelInfo chan; 500 | common::Error err_des = chan.DeSerialize(jchannels_info); 501 | json_object_put(jchannels_info); 502 | if (err_des) { 503 | const std::string err_str = err_des->GetDescription(); 504 | return common::make_errno_error(err_str, EAGAIN); 505 | } 506 | 507 | fApp->PostEvent(new events::ReceiveRuntimeChannelEvent(this, chan)); 508 | return common::ErrnoError(); 509 | } 510 | return common::ErrnoError(); 511 | } 512 | 513 | common::ErrnoError InnerTcpHandler::HandleResponceCommand(Client* client, const protocol::response_t* resp) { 514 | protocol::request_t req; 515 | Client* sclient = static_cast(client); 516 | if (sclient->PopRequestByID(resp->id, &req)) { 517 | if (req.method == CLIENT_ACTIVATE_DEVICE) { 518 | return HandleResponceClientActivateDevice(sclient, resp); 519 | } else if (req.method == CLIENT_LOGIN) { 520 | return HandleResponceClientLogin(sclient, resp); 521 | } else if (req.method == CLIENT_PING) { 522 | return HandleResponceClientPing(sclient, resp); 523 | } else if (req.method == CLIENT_GET_SERVER_INFO) { 524 | return HandleResponceClientGetServerInfo(sclient, resp); 525 | } else if (req.method == CLIENT_GET_CHANNELS) { 526 | return HandleResponceClientGetChannels(sclient, resp); 527 | } else if (req.method == CLIENT_GET_RUNTIME_CHANNEL_INFO) { 528 | return HandleResponceClientGetruntimeChannelInfo(sclient, resp); 529 | } else { 530 | WARNING_LOG() << "HandleResponceServiceCommand not handled command: " << req.method; 531 | } 532 | } 533 | 534 | return common::ErrnoError(); 535 | } 536 | 537 | } // namespace inner 538 | } // namespace client 539 | } // namespace fastotv 540 | -------------------------------------------------------------------------------- /src/client/inner/inner_tcp_handler.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include // for IoLoopObserver 25 | #include // for HostAndPort 26 | 27 | #include // for AuthInfo 28 | #include 29 | #include // for bandwidth_t 30 | 31 | namespace fastotv { 32 | namespace client { 33 | class Client; 34 | namespace bandwidth { 35 | class TcpBandwidthClient; 36 | } 37 | namespace inner { 38 | 39 | class InnerTcpHandler : public common::libev::IoLoopObserver { 40 | public: 41 | enum { 42 | ping_timeout_server = 30 // sec 43 | }; 44 | 45 | explicit InnerTcpHandler(const common::net::HostAndPort& server_host, const commands_info::AuthInfo& auth_info); 46 | ~InnerTcpHandler() override; 47 | 48 | void ActivateRequest(); // should be execute in network thread 49 | void RequestServerInfo(); // should be execute in network thread 50 | void RequestChannels(); // should be execute in network thread 51 | void RequesRuntimeChannelInfo(stream_id_t sid); // should be execute in network thread 52 | void Connect(common::libev::IoLoop* server); // should be execute in network thread 53 | void DisConnect(common::Error err); // should be execute in network thread 54 | 55 | void PreLooped(common::libev::IoLoop* server) override; 56 | void Accepted(common::libev::IoClient* client) override; 57 | void Moved(common::libev::IoLoop* server, common::libev::IoClient* client) override; 58 | void Closed(common::libev::IoClient* client) override; 59 | void DataReceived(common::libev::IoClient* client) override; 60 | void DataReadyToWrite(common::libev::IoClient* client) override; 61 | void PostLooped(common::libev::IoLoop* server) override; 62 | void TimerEmited(common::libev::IoLoop* server, common::libev::timer_id_t id) override; 63 | void Accepted(common::libev::IoChild* child) override; 64 | void Moved(common::libev::IoLoop* server, common::libev::IoChild* child) override; 65 | void ChildStatusChanged(common::libev::IoChild* child, int status, int signal) override; 66 | 67 | protected: 68 | common::ErrnoError HandleInnerDataReceived(Client* client, const std::string& input_command); 69 | common::ErrnoError HandleRequestCommand(Client* client, const protocol::request_t* req); 70 | common::ErrnoError HandleResponceCommand(Client* client, const protocol::response_t* resp); 71 | 72 | private: 73 | common::ErrnoError HandleRequestServerPing(Client* client, const protocol::request_t* req); 74 | common::ErrnoError HandleRequestServerClientInfo(Client* client, const protocol::request_t* req); 75 | common::ErrnoError HandleRequestServerTextNotification(Client* client, const protocol::request_t* req); 76 | common::ErrnoError HandleRequestServerShutdownNotification(Client* client, const protocol::request_t* req); 77 | 78 | common::ErrnoError HandleResponceClientActivateDevice(Client* client, const protocol::response_t* resp); 79 | common::ErrnoError HandleResponceClientLogin(Client* client, const protocol::response_t* resp); 80 | common::ErrnoError HandleResponceClientPing(Client* client, const protocol::response_t* resp); 81 | common::ErrnoError HandleResponceClientGetServerInfo(Client* client, const protocol::response_t* resp); 82 | common::ErrnoError HandleResponceClientGetChannels(Client* client, const protocol::response_t* resp); 83 | common::ErrnoError HandleResponceClientGetruntimeChannelInfo(Client* client, const protocol::response_t* resp); 84 | 85 | Client* inner_connection_; 86 | common::libev::timer_id_t ping_server_id_timer_; 87 | 88 | const common::net::HostAndPort server_host_; 89 | const commands_info::AuthInfo auth_info_; 90 | }; 91 | 92 | } // namespace inner 93 | } // namespace client 94 | } // namespace fastotv 95 | -------------------------------------------------------------------------------- /src/client/inner/inner_tcp_server.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/inner/inner_tcp_server.h" 20 | 21 | namespace fastotv { 22 | namespace client { 23 | namespace inner { 24 | 25 | InnerTcpServer::InnerTcpServer(common::libev::IoLoopObserver* observer) 26 | : IoLoop(new common::libev::LibEvLoop, observer) {} 27 | 28 | const char* InnerTcpServer::ClassName() const { 29 | return "InnerTcpServer"; 30 | } 31 | 32 | bool InnerTcpServer::IsCanBeRegistered(common::libev::IoClient* client) const { 33 | if (!client) { 34 | return false; 35 | } 36 | return true; 37 | } 38 | 39 | common::libev::IoChild* InnerTcpServer::CreateChild() { 40 | NOTREACHED(); 41 | return nullptr; 42 | } 43 | 44 | } // namespace inner 45 | } // namespace client 46 | } // namespace fastotv 47 | -------------------------------------------------------------------------------- /src/client/inner/inner_tcp_server.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include // for IoLoop 22 | 23 | namespace fastotv { 24 | namespace client { 25 | namespace inner { 26 | 27 | class InnerTcpServer : public common::libev::IoLoop { 28 | public: 29 | explicit InnerTcpServer(common::libev::IoLoopObserver* observer); 30 | const char* ClassName() const override; 31 | 32 | bool IsCanBeRegistered(common::libev::IoClient* client) const override; 33 | 34 | protected: 35 | common::libev::IoChild* CreateChild() override; 36 | }; 37 | 38 | } // namespace inner 39 | } // namespace client 40 | } // namespace fastotv 41 | -------------------------------------------------------------------------------- /src/client/inputs/lirc_input_client.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2017 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/inputs/lirc_input_client.h" 20 | 21 | #include // for lirc_code2char, lirc_deinit 22 | 23 | #include 24 | #include 25 | #include 26 | #include // for strdup 27 | #include // for freeifnotnull 28 | 29 | namespace fastotv { 30 | namespace client { 31 | namespace inputs { 32 | 33 | common::ErrnoError LircInit(int* fd, struct lirc_config** cfg) { 34 | if (!fd || !cfg) { 35 | return common::make_errno_error_inval(); 36 | } 37 | 38 | char* copy = common::strdup(PROJECT_NAME_LOWERCASE); // copy for removing warning 39 | int lfd = lirc_init(copy, 1); 40 | common::utils::freeifnotnull(copy); 41 | if (lfd == -1) { 42 | return common::make_errno_error("Lirc init failed!", EAGAIN); 43 | } 44 | 45 | common::ErrnoError err = common::file_system::set_blocking_descriptor(lfd, false); 46 | if (err) { 47 | return err; 48 | } 49 | 50 | lirc_config* lcfg = nullptr; 51 | const std::string absolute_source_dir = common::file_system::absolute_path_from_relative(RELATIVE_SOURCE_DIR); 52 | const std::string lirc_config_path = common::file_system::make_path(absolute_source_dir, LIRCRC_CONFIG_PATH_RELATIVE); 53 | if (lirc_config_path.empty()) { 54 | return common::make_errno_error("Lirc invalid config path!", EAGAIN); 55 | } 56 | 57 | const char* lirc_config_path_ptr = lirc_config_path.c_str(); 58 | char* lirc_config_copy_ptr = common::strdup(lirc_config_path_ptr); // copy for removing warning 59 | int res = lirc_readconfig(lirc_config_copy_ptr, &lcfg, nullptr); 60 | common::utils::freeifnotnull(lirc_config_copy_ptr); 61 | if (res == -1) { 62 | err = LircDeinit(lfd, nullptr); 63 | UNUSED(err); 64 | std::string msg_error = common::MemSPrintf("Could not read LIRC config file: %s", lirc_config_path); 65 | return common::make_errno_error(msg_error, EAGAIN); 66 | } 67 | 68 | *fd = lfd; 69 | *cfg = lcfg; 70 | return common::ErrnoError(); 71 | } 72 | 73 | common::ErrnoError LircDeinit(int fd, struct lirc_config** cfg) { 74 | if (fd == -1) { 75 | return common::ErrnoError(); 76 | } 77 | 78 | if (lirc_deinit() == -1) { 79 | return common::make_errno_error("Lirc deinit failed!", EAGAIN); 80 | } 81 | 82 | if (cfg) { 83 | *cfg = nullptr; 84 | } 85 | return common::ErrnoError(); 86 | } 87 | 88 | LircInputClient::LircInputClient(common::libev::IoLoop* server, int fd, struct lirc_config* cfg) 89 | : base_class(server, fd), cfg_(cfg) {} 90 | 91 | common::Error LircInputClient::ReadWithCallback(read_callback_t cb) { 92 | char* code = nullptr; 93 | int ret; 94 | while ((ret = lirc_nextcode(&code)) == 0 && code != nullptr) { 95 | char* c = nullptr; 96 | while ((ret = lirc_code2char(cfg_, code, &c)) == 0 && c != nullptr) { 97 | if (cb) { 98 | cb(c); 99 | } 100 | } 101 | free(code); 102 | if (ret == -1) { 103 | break; 104 | } 105 | } 106 | 107 | return common::Error(); 108 | } 109 | 110 | common::ErrnoError LircInputClient::DoClose() { 111 | return LircDeinit(GetFd(), &cfg_); 112 | } 113 | 114 | } // namespace inputs 115 | } // namespace client 116 | } // namespace fastotv 117 | -------------------------------------------------------------------------------- /src/client/inputs/lirc_input_client.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | struct lirc_config; 27 | 28 | namespace common { 29 | namespace libev { 30 | class IoLoop; 31 | } 32 | } // namespace common 33 | 34 | namespace fastotv { 35 | namespace client { 36 | namespace inputs { 37 | 38 | common::ErrnoError LircInit(int* fd, struct lirc_config** cfg) WARN_UNUSED_RESULT; 39 | common::ErrnoError LircDeinit(int fd, struct lirc_config** cfg) WARN_UNUSED_RESULT; 40 | 41 | class LircInputClient : public common::libev::DescriptorClient { 42 | public: 43 | typedef common::libev::DescriptorClient base_class; 44 | typedef std::function read_callback_t; 45 | LircInputClient(common::libev::IoLoop* server, int fd, struct lirc_config* cfg); 46 | 47 | common::Error ReadWithCallback(read_callback_t cb) WARN_UNUSED_RESULT; 48 | 49 | private: 50 | common::ErrnoError DoClose() override; 51 | 52 | using base_class::Read; 53 | using base_class::Write; 54 | 55 | struct lirc_config* cfg_; 56 | }; 57 | } // namespace inputs 58 | } // namespace client 59 | } // namespace fastotv 60 | -------------------------------------------------------------------------------- /src/client/ioservice.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/ioservice.h" 20 | 21 | #include // for string 22 | 23 | #include // for fApp 24 | #include // for DEBUG_MSG_ERROR, Error 25 | #include // for COMPACT_LOG_FILE_CRIT 26 | #include // for THREAD_MANAGER 27 | 28 | #include "client/inner/inner_tcp_handler.h" // for InnerTcpHandler, StartC... 29 | #include "client/inner/inner_tcp_server.h" // for InnerTcpServer 30 | 31 | #ifdef HAVE_LIRC 32 | #include // for ConvertFromString, Lirc... 33 | #include "client/inputs/lirc_input_client.h" // for LircInit, LircInputClient 34 | #endif 35 | 36 | namespace common { 37 | namespace libev { 38 | class IoClient; 39 | } 40 | } // namespace common 41 | 42 | namespace fastotv { 43 | namespace client { 44 | 45 | namespace { 46 | class PrivateHandler : public inner::InnerTcpHandler { 47 | public: 48 | typedef inner::InnerTcpHandler base_class; 49 | explicit PrivateHandler(const common::net::HostAndPort& server_host, const commands_info::AuthInfo& auth_info) 50 | : base_class(server_host, auth_info) 51 | #ifdef HAVE_LIRC 52 | , 53 | client_(nullptr) 54 | #endif 55 | { 56 | } 57 | 58 | ~PrivateHandler() override {} 59 | 60 | void PreLooped(common::libev::IoLoop* server) override { 61 | #ifdef HAVE_LIRC 62 | int fd = INVALID_DESCRIPTOR; 63 | struct lirc_config* lcd = nullptr; 64 | common::ErrnoError err = inputs::LircInit(&fd, &lcd); 65 | if (err) { 66 | DEBUG_MSG_ERROR(err, common::logging::LOG_LEVEL_ERR); 67 | } else { 68 | inputs::LircInputClient* client = new inputs::LircInputClient(server, fd, lcd); 69 | if (server->RegisterClient(client)) { 70 | client_ = client; 71 | } 72 | } 73 | #endif 74 | base_class::PreLooped(server); 75 | } 76 | 77 | void Closed(common::libev::IoClient* client) override { 78 | #ifdef HAVE_LIRC 79 | if (client == client_) { 80 | client_ = nullptr; 81 | return; 82 | } 83 | #endif 84 | base_class::Closed(client); 85 | } 86 | 87 | void DataReceived(common::libev::IoClient* client) override { 88 | #ifdef HAVE_LIRC 89 | if (client == client_) { 90 | auto cb = [this](const std::string& code) { 91 | LircCode lcode; 92 | if (!common::ConvertFromString(code, &lcode)) { 93 | WARNING_LOG() << "Unknown lirc code: " << code; 94 | return; 95 | } 96 | 97 | fastoplayer::gui::events::LircPressInfo linf; 98 | linf.code = lcode; 99 | fastoplayer::gui::events::LircPressEvent* levent = new fastoplayer::gui::events::LircPressEvent(this, linf); 100 | fApp->PostEvent(levent); 101 | }; 102 | client_->ReadWithCallback(cb); 103 | return; 104 | } 105 | #endif 106 | base_class::DataReceived(client); 107 | } 108 | 109 | void PostLooped(common::libev::IoLoop* server) override { 110 | UNUSED(server); 111 | #ifdef HAVE_LIRC 112 | if (client_) { 113 | inputs::LircInputClient* connection = client_; 114 | connection->Close(); 115 | delete connection; 116 | } 117 | #endif 118 | base_class::PostLooped(server); 119 | } 120 | #ifdef HAVE_LIRC 121 | inputs::LircInputClient* client_; 122 | #endif 123 | }; 124 | } // namespace 125 | 126 | IoService::IoService(const commands_info::AuthInfo& ainf, const common::net::HostAndPort& server_host) 127 | : ILoopController(), 128 | ainf_(ainf), 129 | server_host_(server_host), 130 | loop_thread_(THREAD_MANAGER()->CreateThread(&IoService::Exec, this)) {} 131 | 132 | bool IoService::IsRunning() const { 133 | return loop_->IsRunning(); 134 | } 135 | 136 | void IoService::Start() { 137 | ILoopController::Start(); 138 | } 139 | 140 | void IoService::Stop() { 141 | ILoopController::Stop(); 142 | } 143 | 144 | IoService::~IoService() {} 145 | 146 | void IoService::ConnectToServer() const { 147 | PrivateHandler* handler = static_cast(handler_); 148 | client::inner::InnerTcpServer* server = static_cast(loop_); 149 | if (handler) { 150 | auto cb = [handler, server]() { handler->Connect(server); }; 151 | ExecInLoopThread(cb); 152 | } 153 | } 154 | 155 | void IoService::ActivateRequest() const { 156 | PrivateHandler* handler = static_cast(handler_); 157 | if (handler) { 158 | auto cb = [handler]() { handler->ActivateRequest(); }; 159 | ExecInLoopThread(cb); 160 | } 161 | } 162 | 163 | void IoService::DisconnectFromServer() const { 164 | PrivateHandler* handler = static_cast(handler_); 165 | if (handler) { 166 | auto cb = [handler]() { handler->DisConnect(common::Error()); }; 167 | ExecInLoopThread(cb); 168 | } 169 | } 170 | 171 | void IoService::RequestServerInfo() const { 172 | PrivateHandler* handler = static_cast(handler_); 173 | if (handler) { 174 | auto cb = [handler]() { handler->RequestServerInfo(); }; 175 | ExecInLoopThread(cb); 176 | } 177 | } 178 | 179 | void IoService::RequestChannels() const { 180 | PrivateHandler* handler = static_cast(handler_); 181 | if (handler) { 182 | auto cb = [handler]() { handler->RequestChannels(); }; 183 | ExecInLoopThread(cb); 184 | } 185 | } 186 | 187 | void IoService::RequesRuntimeChannelInfo(stream_id_t sid) const { 188 | PrivateHandler* handler = static_cast(handler_); 189 | if (handler) { 190 | auto cb = [handler, sid]() { handler->RequesRuntimeChannelInfo(sid); }; 191 | ExecInLoopThread(cb); 192 | } 193 | } 194 | 195 | common::libev::IoLoopObserver* IoService::CreateHandler() { 196 | return new PrivateHandler(server_host_, ainf_); 197 | } 198 | 199 | common::libev::IoLoop* IoService::CreateServer(common::libev::IoLoopObserver* handler) { 200 | client::inner::InnerTcpServer* serv = new client::inner::InnerTcpServer(handler); 201 | serv->SetName("local_inner_server"); 202 | return serv; 203 | } 204 | 205 | void IoService::HandleStarted() { 206 | ignore_result(loop_thread_->Start()); 207 | } 208 | 209 | void IoService::HandleStopped() { 210 | loop_thread_->JoinAndGet(); 211 | } 212 | 213 | } // namespace client 214 | } // namespace fastotv 215 | -------------------------------------------------------------------------------- /src/client/ioservice.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | #include // for IoLoop 24 | #include // for IoLoopObserver 25 | #include // for ILoopController 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | namespace common { 32 | namespace threads { 33 | template 34 | class Thread; 35 | } 36 | } // namespace common 37 | 38 | namespace fastotv { 39 | namespace client { 40 | 41 | class IoService : public common::libev::ILoopController { 42 | public: 43 | IoService(const commands_info::AuthInfo& ainf, const common::net::HostAndPort& server_host); 44 | ~IoService() override; 45 | 46 | bool IsRunning() const; 47 | void Start(); 48 | void Stop(); 49 | 50 | void ConnectToServer() const; 51 | void ActivateRequest() const; 52 | void DisconnectFromServer() const; 53 | void RequestServerInfo() const; 54 | void RequestChannels() const; 55 | void RequesRuntimeChannelInfo(stream_id_t sid) const; 56 | 57 | private: 58 | using ILoopController::Exec; 59 | 60 | common::libev::IoLoopObserver* CreateHandler() override; 61 | common::libev::IoLoop* CreateServer(common::libev::IoLoopObserver* handler) override; 62 | 63 | void HandleStarted() override; 64 | void HandleStopped() override; 65 | 66 | const commands_info::AuthInfo ainf_; 67 | const common::net::HostAndPort server_host_; 68 | std::shared_ptr> loop_thread_; 69 | }; 70 | 71 | } // namespace client 72 | } // namespace fastotv 73 | -------------------------------------------------------------------------------- /src/client/live_stream/playlist_entry.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/live_stream/playlist_entry.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #define IMG_UNKNOWN_CHANNEL_PATH_RELATIVE "share/resources/unknown_channel.png" 27 | 28 | #define ICON_FILE_NAME "icon" 29 | 30 | namespace fastotv { 31 | namespace client { 32 | 33 | PlaylistEntry::PlaylistEntry() : info_(), icon_(), cache_dir_() {} 34 | 35 | PlaylistEntry::PlaylistEntry(const std::string& cache_root_dir, const commands_info::ChannelInfo& info) 36 | : info_(info), rinfo_(), icon_(), cache_dir_() { 37 | stream_id_t id = info_.GetStreamID(); 38 | cache_dir_ = common::file_system::make_path(cache_root_dir, id); 39 | } 40 | 41 | std::string PlaylistEntry::GetCacheDir() const { 42 | return cache_dir_; 43 | } 44 | 45 | std::string PlaylistEntry::GetIconPath() const { 46 | commands_info::EpgInfo epg = info_.GetEpg(); 47 | common::uri::GURL uri = epg.GetIconUrl(); 48 | bool is_unknown_icon = uri == "https://fastocloud.com/images/unknown_channel.png"; 49 | if (is_unknown_icon) { 50 | const std::string absolute_source_dir = 51 | common::file_system::absolute_path_from_relative(RELATIVE_SOURCE_DIR, common::file_system::app_pwd()); // + 52 | return common::file_system::make_path(absolute_source_dir, IMG_UNKNOWN_CHANNEL_PATH_RELATIVE); 53 | } 54 | std::string dir = GetCacheDir(); 55 | return common::file_system::make_path(dir, ICON_FILE_NAME); 56 | } 57 | 58 | ChannelDescription PlaylistEntry::GetChannelDescription() const { 59 | std::string decr = "N/A"; 60 | commands_info::ChannelInfo url = GetChannelInfo(); 61 | commands_info::EpgInfo epg = url.GetEpg(); 62 | commands_info::ProgrammeInfo prog; 63 | if (epg.FindProgrammeByTime(common::time::current_utc_mstime(), &prog)) { 64 | decr = prog.GetTitle(); 65 | } 66 | 67 | return {epg.GetDisplayName(), decr, GetIcon()}; 68 | } 69 | 70 | void PlaylistEntry::SetIcon(channel_icon_t icon) { 71 | icon_ = icon; 72 | } 73 | 74 | channel_icon_t PlaylistEntry::GetIcon() const { 75 | return icon_; 76 | } 77 | 78 | commands_info::ChannelInfo PlaylistEntry::GetChannelInfo() const { 79 | return info_; 80 | } 81 | 82 | void PlaylistEntry::SetRuntimeChannelInfo(const commands_info::RuntimeChannelInfo& rinfo) { 83 | rinfo_ = rinfo; 84 | } 85 | 86 | commands_info::RuntimeChannelInfo PlaylistEntry::GetRuntimeChannelInfo() const { 87 | return rinfo_; 88 | } 89 | 90 | } // namespace client 91 | } // namespace fastotv 92 | -------------------------------------------------------------------------------- /src/client/live_stream/playlist_entry.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | namespace fastoplayer { 28 | namespace draw { 29 | class SurfaceSaver; 30 | } 31 | } // namespace fastoplayer 32 | 33 | namespace fastotv { 34 | namespace client { 35 | 36 | typedef std::shared_ptr channel_icon_t; 37 | 38 | struct ChannelDescription { 39 | std::string title; 40 | std::string description; 41 | channel_icon_t icon; 42 | }; 43 | 44 | class PlaylistEntry { 45 | public: 46 | PlaylistEntry(); 47 | PlaylistEntry(const std::string& cache_root_dir, const commands_info::ChannelInfo& info); 48 | 49 | commands_info::ChannelInfo GetChannelInfo() const; 50 | 51 | void SetRuntimeChannelInfo(const commands_info::RuntimeChannelInfo& rinfo); 52 | commands_info::RuntimeChannelInfo GetRuntimeChannelInfo() const; 53 | 54 | void SetIcon(channel_icon_t icon); 55 | channel_icon_t GetIcon() const; 56 | 57 | std::string GetCacheDir() const; 58 | std::string GetIconPath() const; 59 | 60 | ChannelDescription GetChannelDescription() const; 61 | 62 | private: 63 | commands_info::ChannelInfo info_; 64 | commands_info::RuntimeChannelInfo rinfo_; 65 | 66 | channel_icon_t icon_; 67 | std::string cache_dir_; 68 | }; 69 | 70 | } // namespace client 71 | } // namespace fastotv 72 | -------------------------------------------------------------------------------- /src/client/live_stream/playlist_window.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/live_stream/playlist_window.h" 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | namespace fastotv { 32 | namespace client { 33 | 34 | PlaylistWindow::PlaylistWindow(const SDL_Color& back_ground_color, Window* parent) 35 | : base_class(back_ground_color, parent), play_list_(nullptr) {} 36 | 37 | PlaylistWindow::~PlaylistWindow() {} 38 | 39 | void PlaylistWindow::SetPlaylist(const playlist_t* pl) { 40 | play_list_ = pl; 41 | } 42 | 43 | const PlaylistWindow::playlist_t* PlaylistWindow::GetPlaylist() const { 44 | return play_list_; 45 | } 46 | 47 | size_t PlaylistWindow::GetRowCount() const { 48 | if (!play_list_) { 49 | return 0; 50 | } 51 | return play_list_->size(); 52 | } 53 | 54 | void PlaylistWindow::DrawRow(SDL_Renderer* render, size_t pos, bool active, bool hover, const SDL_Rect& row_rect) { 55 | UNUSED(active); 56 | UNUSED(hover); 57 | 58 | if (!play_list_) { 59 | return; 60 | } 61 | 62 | SDL_Rect number_rect = {row_rect.x, row_rect.y, channel_number_width, row_rect.h}; 63 | std::string number_str = common::ConvertToString(pos + 1); 64 | DrawText(render, number_str, number_rect, PlaylistWindow::CENTER_TEXT); 65 | 66 | ChannelDescription descr = play_list_->operator[](pos).GetChannelDescription(); 67 | channel_icon_t icon = descr.icon; 68 | int shift = channel_number_width; 69 | if (icon) { 70 | SDL_Texture* img = icon->GetTexture(render); 71 | if (img) { 72 | SDL_Rect icon_rect = {row_rect.x + shift, row_rect.y, row_rect.h, row_rect.h}; 73 | SDL_RenderCopy(render, img, nullptr, &icon_rect); 74 | } 75 | } 76 | shift += row_rect.h + space_width; // in any case shift should be 77 | 78 | int text_width = row_rect.w - shift; 79 | std::string title_line = 80 | fastoplayer::draw::DotText(common::MemSPrintf("Title: %s", descr.title), GetFont(), text_width); 81 | std::string description_line = 82 | fastoplayer::draw::DotText(common::MemSPrintf("Description: %s", descr.description), GetFont(), text_width); 83 | 84 | std::string line_text = common::MemSPrintf( 85 | "%s\n" 86 | "%s", 87 | title_line, description_line); 88 | SDL_Rect text_rect = {row_rect.x + shift, row_rect.y, text_width, row_rect.h}; 89 | DrawText(render, line_text, text_rect, GetDrawType()); 90 | } 91 | 92 | } // namespace client 93 | } // namespace fastotv 94 | -------------------------------------------------------------------------------- /src/client/live_stream/playlist_window.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "client/live_stream/playlist_entry.h" 27 | 28 | namespace fastotv { 29 | namespace client { 30 | 31 | class PlaylistWindow : public fastoplayer::gui::IListBox { 32 | public: 33 | typedef fastoplayer::gui::IListBox base_class; 34 | typedef std::vector playlist_t; 35 | enum { channel_number_width = 60, space_width = 10 }; 36 | explicit PlaylistWindow(const SDL_Color& back_ground_color, Window* parent = nullptr); 37 | ~PlaylistWindow() override; 38 | 39 | void SetPlaylist(const playlist_t* pl); 40 | const playlist_t* GetPlaylist() const; 41 | 42 | size_t GetRowCount() const override; 43 | 44 | protected: 45 | void DrawRow(SDL_Renderer* render, size_t pos, bool active, bool hover, const SDL_Rect& row_rect) override; 46 | 47 | private: 48 | const playlist_t* play_list_; // pointer 49 | }; 50 | 51 | } // namespace client 52 | } // namespace fastotv 53 | -------------------------------------------------------------------------------- /src/client/load_config.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/load_config.h" 20 | 21 | #include // for strcmp 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include // for HWAccelID 32 | 33 | #include "inih/ini.h" // for ini_parse 34 | 35 | #include "client/cmdutils.h" 36 | 37 | #define CONFIG_USER_OPTIONS "user_options" 38 | #define CONFIG_USER_OPTIONS_LOGIN_FIELD "login" 39 | #define CONFIG_USER_OPTIONS_PASSWORD_FIELD "password" 40 | #define CONFIG_USER_OPTIONS_DEVICE_ID_FIELD "device_id" 41 | 42 | #define CONFIG_SERVER_OPTIONS "server_options" 43 | #define CONFIG_SERVER_OPTIONS_SERVER_FIELD "server" 44 | 45 | #define CONFIG_MAIN_OPTIONS "main_options" 46 | #define CONFIG_MAIN_OPTIONS_LOG_LEVEL_FIELD "loglevel" 47 | #define CONFIG_MAIN_OPTIONS_POWEROFF_ON_EXIT_FIELD "poweroffonexit" 48 | 49 | #define CONFIG_PLAYER_OPTIONS "player_options" 50 | #define CONFIG_PLAYER_OPTIONS_WIDTH_FIELD "width" 51 | #define CONFIG_PLAYER_OPTIONS_HEIGHT_FIELD "height" 52 | #define CONFIG_PLAYER_OPTIONS_FULLSCREEN_FIELD "fullscreen" 53 | #define CONFIG_PLAYER_OPTIONS_VOLUME_FIELD "volume" 54 | #define CONFIG_PLAYER_OPTIONS_LAST_SHOWED_CHANNEL_ID_FIELD "last_showed_channel_id" 55 | 56 | #define CONFIG_APP_OPTIONS "app_options" 57 | #define CONFIG_APP_OPTIONS_AST_FIELD "ast" 58 | #define CONFIG_APP_OPTIONS_VST_FIELD "vst" 59 | #define CONFIG_APP_OPTIONS_FAST_FIELD "fast" 60 | #define CONFIG_APP_OPTIONS_GENPTS_FIELD "genpts" 61 | #define CONFIG_APP_OPTIONS_LOWRES_FIELD "lowres" 62 | #define CONFIG_APP_OPTIONS_SYNC_FIELD "sync" 63 | #define CONFIG_APP_OPTIONS_FRAMEDROP_FIELD "framedrop" 64 | #define CONFIG_APP_OPTIONS_BYTES_FIELD "bytes" 65 | #define CONFIG_APP_OPTIONS_INFBUF_FIELD "infbuf" 66 | #define CONFIG_APP_OPTIONS_VF_FIELD "vf" 67 | #define CONFIG_APP_OPTIONS_AF_FIELD "af" 68 | #define CONFIG_APP_OPTIONS_VN_FIELD "vn" 69 | #define CONFIG_APP_OPTIONS_AN_FIELD "an" 70 | #define CONFIG_APP_OPTIONS_ACODEC_FIELD "acodec" 71 | #define CONFIG_APP_OPTIONS_VCODEC_FIELD "vcodec" 72 | #define CONFIG_APP_OPTIONS_HWACCEL_FIELD "hwaccel" 73 | #define CONFIG_APP_OPTIONS_HWACCEL_DEVICE_FIELD "hwaccel_device" 74 | #define CONFIG_APP_OPTIONS_HWACCEL_OUTPUT_FORMAT_FIELD "hwaccel_output_format" 75 | #define CONFIG_APP_OPTIONS_AUTOROTATE_FIELD "autorotate" 76 | 77 | // vaapi args: -hwaccel vaapi -hwaccel_device /dev/dri/card0 78 | // vdpau args: -hwaccel vdpau 79 | // scale output: -vf scale=1920x1080 80 | // deinterlace output: -vf yadif 81 | 82 | /* 83 | [server_options] 84 | server=fastotv.com:6000 85 | 86 | [user_options] 87 | login=anon@fastogt.com 88 | password=md5_hash 89 | device_id=unique_id 90 | 91 | [main_options] 92 | loglevel=INFO ["EMERG", "ALLERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"] 93 | poweroffonexit=false [true,false] 94 | 95 | [app_options] 96 | ast=0 [0, INT_MAX] 97 | vst=0 [0, INT_MAX] 98 | stats=true [true,false] 99 | fast=false [true,false] 100 | genpts=false [true,false] 101 | lowres=0 [0, INT_MAX] 102 | sync=audio [audio, video] 103 | framedrop=-1 [-1, 0, 1] 104 | infbuf=-1 [-1, 0, 1] 105 | vf=std::string() [] 106 | af=std::string() [] 107 | acodec=std::string() [] 108 | vcodec=std::string() [] 109 | hwaccel=none [none, auto, vdpau, dxva2, vda, 110 | videotoolbox, qsv, vaapi, cuvid] 111 | hwaccel_device=std::string() [] 112 | hwaccel_output_format=std::string() [] 113 | autorotate=false [true,false] 114 | 115 | [player_options] 116 | width=0 [0, INT_MAX] 117 | height=0 [0, INT_MAX] 118 | fullscreen=false [true,false] 119 | volume=100 [0,100] 120 | exitonkeydown=false [true,false] 121 | exitonmousedown=false [true,false] 122 | */ 123 | 124 | namespace fastotv { 125 | namespace client { 126 | 127 | namespace { 128 | 129 | int ini_handler_fasto(void* user, const char* section, const char* name, const char* value) { 130 | FastoTVConfig* pconfig = reinterpret_cast(user); 131 | size_t value_len = strlen(value); 132 | if (value_len == 0) { // skip empty fields 133 | return 0; 134 | } 135 | 136 | #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 137 | if (MATCH(CONFIG_SERVER_OPTIONS, CONFIG_SERVER_OPTIONS_SERVER_FIELD)) { 138 | common::net::HostAndPort hs; 139 | if (common::ConvertFromString(value, &hs)) { 140 | pconfig->server = hs; 141 | } 142 | return 1; 143 | } else if (MATCH(CONFIG_USER_OPTIONS, CONFIG_USER_OPTIONS_LOGIN_FIELD)) { 144 | pconfig->auth_options.SetLogin(value); 145 | return 1; 146 | } else if (MATCH(CONFIG_USER_OPTIONS, CONFIG_USER_OPTIONS_PASSWORD_FIELD)) { 147 | pconfig->auth_options.SetPassword(value); 148 | return 1; 149 | } else if (MATCH(CONFIG_USER_OPTIONS, CONFIG_USER_OPTIONS_DEVICE_ID_FIELD)) { 150 | pconfig->auth_options.SetDeviceID(value); 151 | return 1; 152 | } else if (MATCH(CONFIG_MAIN_OPTIONS, CONFIG_MAIN_OPTIONS_LOG_LEVEL_FIELD)) { 153 | common::logging::LOG_LEVEL lg; 154 | if (common::logging::text_to_log_level(value, &lg)) { 155 | pconfig->loglevel = lg; 156 | } 157 | return 1; 158 | } else if (MATCH(CONFIG_MAIN_OPTIONS, CONFIG_MAIN_OPTIONS_POWEROFF_ON_EXIT_FIELD)) { 159 | bool exit; 160 | if (parse_bool(value, &exit)) { 161 | pconfig->power_off_on_exit = exit; 162 | } 163 | return 1; 164 | } else if (MATCH(CONFIG_PLAYER_OPTIONS, CONFIG_PLAYER_OPTIONS_WIDTH_FIELD)) { 165 | int width; 166 | if (parse_number(value, -1, std::numeric_limits::max(), &width)) { 167 | pconfig->player_options.screen_size.set_width(width); 168 | } 169 | return 1; 170 | } else if (MATCH(CONFIG_PLAYER_OPTIONS, CONFIG_PLAYER_OPTIONS_HEIGHT_FIELD)) { 171 | int height; 172 | if (parse_number(value, -1, std::numeric_limits::max(), &height)) { 173 | pconfig->player_options.screen_size.set_width(height); 174 | } 175 | return 1; 176 | } else if (MATCH(CONFIG_PLAYER_OPTIONS, CONFIG_PLAYER_OPTIONS_FULLSCREEN_FIELD)) { 177 | bool is_full_screen; 178 | if (parse_bool(value, &is_full_screen)) { 179 | pconfig->player_options.is_full_screen = is_full_screen; 180 | } 181 | return 1; 182 | } else if (MATCH(CONFIG_PLAYER_OPTIONS, CONFIG_PLAYER_OPTIONS_VOLUME_FIELD)) { 183 | int volume; 184 | if (parse_number(value, 0, 100, &volume)) { 185 | pconfig->player_options.audio_volume = static_cast(volume); 186 | } 187 | return 1; 188 | } else if (MATCH(CONFIG_PLAYER_OPTIONS, CONFIG_PLAYER_OPTIONS_LAST_SHOWED_CHANNEL_ID_FIELD)) { 189 | pconfig->player_options.last_showed_channel_id = value; 190 | return 1; 191 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_AST_FIELD)) { 192 | pconfig->app_options.wanted_stream_spec[AVMEDIA_TYPE_AUDIO] = value; 193 | return 1; 194 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_VST_FIELD)) { 195 | pconfig->app_options.wanted_stream_spec[AVMEDIA_TYPE_VIDEO] = value; 196 | return 1; 197 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_FAST_FIELD)) { 198 | bool fast; 199 | if (parse_bool(value, &fast)) { 200 | pconfig->app_options.fast = fast; 201 | } 202 | return 1; 203 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_GENPTS_FIELD)) { 204 | bool genpts; 205 | if (parse_bool(value, &genpts)) { 206 | pconfig->app_options.genpts = genpts; 207 | } 208 | return 1; 209 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_LOWRES_FIELD)) { 210 | int lowres; 211 | if (parse_number(value, std::numeric_limits::min(), std::numeric_limits::max(), &lowres)) { 212 | pconfig->app_options.lowres = lowres; 213 | } 214 | return 1; 215 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_SYNC_FIELD)) { 216 | if (strcmp(value, "audio") == 0) { 217 | pconfig->app_options.av_sync_type = fastoplayer::media::AV_SYNC_AUDIO_MASTER; 218 | } else if (strcmp(value, "video") == 0) { 219 | pconfig->app_options.av_sync_type = fastoplayer::media::AV_SYNC_VIDEO_MASTER; 220 | } else { 221 | return 0; 222 | } 223 | return 1; 224 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_FRAMEDROP_FIELD)) { 225 | if (strcmp(value, "auto") == 0) { 226 | pconfig->app_options.framedrop = fastoplayer::media::FRAME_DROP_AUTO; 227 | } else if (strcmp(value, "off") == 0) { 228 | pconfig->app_options.framedrop = fastoplayer::media::FRAME_DROP_OFF; 229 | } else if (strcmp(value, "on") == 0) { 230 | pconfig->app_options.framedrop = fastoplayer::media::FRAME_DROP_ON; 231 | } else { 232 | return 0; 233 | } 234 | 235 | return 1; 236 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_BYTES_FIELD)) { 237 | if (strcmp(value, "auto") == 0) { 238 | pconfig->app_options.seek_by_bytes = fastoplayer::media::SEEK_AUTO; 239 | } else if (strcmp(value, "off") == 0) { 240 | pconfig->app_options.seek_by_bytes = fastoplayer::media::SEEK_BY_BYTES_OFF; 241 | } else if (strcmp(value, "on") == 0) { 242 | pconfig->app_options.seek_by_bytes = fastoplayer::media::SEEK_BY_BYTES_ON; 243 | } else { 244 | return 0; 245 | } 246 | 247 | return 1; 248 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_INFBUF_FIELD)) { 249 | int inf; 250 | if (parse_number(value, -1, 1, &inf)) { 251 | pconfig->app_options.infinite_buffer = inf; 252 | } 253 | return 1; 254 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_VN_FIELD)) { 255 | bool disable_video; 256 | if (parse_bool(value, &disable_video)) { 257 | pconfig->app_options.enable_video = !disable_video; 258 | } 259 | return 1; 260 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_AN_FIELD)) { 261 | bool disable_audio; 262 | if (parse_bool(value, &disable_audio)) { 263 | pconfig->app_options.enable_audio = !disable_audio; 264 | } 265 | return 1; 266 | #if CONFIG_AVFILTER 267 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_VF_FIELD)) { 268 | std::vector tokens; 269 | size_t vf_count = common::Tokenize(value, ",", &tokens); 270 | for (size_t i = 0; i < vf_count; ++i) { 271 | std::string arg_copy = tokens[i]; 272 | size_t del = arg_copy.find_first_of('='); 273 | if (del != std::string::npos) { 274 | std::string key = arg_copy.substr(0, del); 275 | std::string value = arg_copy.substr(del + 1); 276 | if (key == "scale") { 277 | common::draw::Size sz; 278 | if (common::ConvertFromString(value, &sz)) { 279 | pconfig->player_options.screen_size = sz; 280 | } 281 | } 282 | } 283 | } 284 | pconfig->app_options.vfilters = value; 285 | return 1; 286 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_AF_FIELD)) { 287 | pconfig->app_options.afilters = value; 288 | return 1; 289 | #endif 290 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_ACODEC_FIELD)) { 291 | pconfig->app_options.audio_codec_name = value; 292 | return 1; 293 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_VCODEC_FIELD)) { 294 | pconfig->app_options.video_codec_name = value; 295 | return 1; 296 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_HWACCEL_FIELD)) { 297 | fastoplayer::media::HWAccelID hwid; 298 | fastoplayer::media::HWDeviceType dtype; 299 | if (fastoplayer::media::HWAccelIDFromString(value, &hwid, &dtype)) { 300 | pconfig->app_options.hwaccel_id = hwid; 301 | pconfig->app_options.hwaccel_device_type = dtype; 302 | } 303 | return 1; 304 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_HWACCEL_DEVICE_FIELD)) { 305 | pconfig->app_options.hwaccel_device = value; 306 | return 1; 307 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_HWACCEL_OUTPUT_FORMAT_FIELD)) { 308 | pconfig->app_options.hwaccel_output_format = value; 309 | return 1; 310 | } else if (MATCH(CONFIG_APP_OPTIONS, CONFIG_APP_OPTIONS_AUTOROTATE_FIELD)) { 311 | bool autorotate; 312 | if (parse_bool(value, &autorotate)) { 313 | pconfig->app_options.autorotate = autorotate; 314 | } 315 | return 1; 316 | } else { 317 | return 0; /* unknown section/name, error */ 318 | } 319 | } 320 | } // namespace 321 | 322 | common::ErrnoError load_config_file(const std::string& config_absolute_path, FastoTVConfig* options) { 323 | if (!options) { 324 | return common::make_errno_error_inval(); 325 | } 326 | 327 | std::string copy_config_absolute_path = config_absolute_path; 328 | if (!common::file_system::is_file_exist(config_absolute_path)) { 329 | const std::string absolute_source_dir = 330 | common::file_system::absolute_path_from_relative(RELATIVE_SOURCE_DIR, common::file_system::app_pwd()); // + 331 | copy_config_absolute_path = common::file_system::make_path(absolute_source_dir, CONFIG_FILE_PATH_RELATIVE); 332 | } 333 | 334 | if (!copy_config_absolute_path.empty()) { 335 | int res = ini_parse(copy_config_absolute_path.c_str(), ini_handler_fasto, options); 336 | if (res == -1) { 337 | WARNING_LOG() << "Can't open config file path: " << copy_config_absolute_path; 338 | } 339 | } 340 | return common::ErrnoError(); 341 | } 342 | 343 | common::ErrnoError save_config_file(const std::string& config_absolute_path, FastoTVConfig* options) { 344 | if (!options || config_absolute_path.empty()) { 345 | return common::make_errno_error_inval(); 346 | } 347 | 348 | common::file_system::FileGuard config_save_file; 349 | common::ErrnoError err = config_save_file.Open(config_absolute_path, "w"); 350 | if (err) { 351 | return err; 352 | } 353 | 354 | config_save_file.Write("[" CONFIG_SERVER_OPTIONS "]\n"); 355 | const std::string host_and_port_str = common::ConvertToString(options->server); 356 | config_save_file.WriteFormated(CONFIG_SERVER_OPTIONS_SERVER_FIELD "=%s\n", host_and_port_str); 357 | 358 | config_save_file.Write("[" CONFIG_USER_OPTIONS "]\n"); 359 | config_save_file.WriteFormated(CONFIG_USER_OPTIONS_LOGIN_FIELD "=%s\n", options->auth_options.GetLogin()); 360 | config_save_file.WriteFormated(CONFIG_USER_OPTIONS_PASSWORD_FIELD "=%s\n", options->auth_options.GetPassword()); 361 | config_save_file.WriteFormated(CONFIG_USER_OPTIONS_DEVICE_ID_FIELD "=%s\n", options->auth_options.GetDeviceID()); 362 | 363 | config_save_file.Write("[" CONFIG_MAIN_OPTIONS "]\n"); 364 | config_save_file.WriteFormated(CONFIG_MAIN_OPTIONS_LOG_LEVEL_FIELD "=%s\n", 365 | common::logging::log_level_to_text(options->loglevel)); 366 | config_save_file.WriteFormated(CONFIG_MAIN_OPTIONS_POWEROFF_ON_EXIT_FIELD "=%s\n", 367 | common::ConvertToString(options->power_off_on_exit)); 368 | 369 | config_save_file.Write("[" CONFIG_APP_OPTIONS "]\n"); 370 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_AST_FIELD "=%s\n", 371 | options->app_options.wanted_stream_spec[AVMEDIA_TYPE_AUDIO]); 372 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_VST_FIELD "=%s\n", 373 | options->app_options.wanted_stream_spec[AVMEDIA_TYPE_VIDEO]); 374 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_FAST_FIELD "=%s\n", 375 | common::ConvertToString(options->app_options.fast)); 376 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_GENPTS_FIELD "=%s\n", 377 | common::ConvertToString(options->app_options.genpts)); 378 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_LOWRES_FIELD "=%d\n", options->app_options.lowres); 379 | config_save_file.WriteFormated( 380 | CONFIG_APP_OPTIONS_SYNC_FIELD "=%s\n", 381 | options->app_options.av_sync_type == fastoplayer::media::AV_SYNC_AUDIO_MASTER ? "audio" : "video"); 382 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_FRAMEDROP_FIELD "=%d\n", 383 | static_cast(options->app_options.framedrop)); 384 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_BYTES_FIELD "=%d\n", 385 | static_cast(options->app_options.seek_by_bytes)); 386 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_INFBUF_FIELD "=%d\n", options->app_options.infinite_buffer); 387 | 388 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_VN_FIELD "=%s\n", 389 | common::ConvertToString(!options->app_options.enable_video)); 390 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_AN_FIELD "=%s\n", 391 | common::ConvertToString(!options->app_options.enable_audio)); 392 | #if CONFIG_AVFILTER 393 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_VF_FIELD "=%s\n", options->app_options.vfilters); 394 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_AF_FIELD "=%s\n", options->app_options.afilters); 395 | #endif 396 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_ACODEC_FIELD "=%s\n", options->app_options.audio_codec_name); 397 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_VCODEC_FIELD "=%s\n", options->app_options.video_codec_name); 398 | config_save_file.WriteFormated( 399 | CONFIG_APP_OPTIONS_HWACCEL_FIELD "=%s\n", 400 | fastoplayer::media::HWAccelIDToString(options->app_options.hwaccel_id, options->app_options.hwaccel_device_type)); 401 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_HWACCEL_DEVICE_FIELD "=%s\n", options->app_options.hwaccel_device); 402 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_HWACCEL_OUTPUT_FORMAT_FIELD "=%s\n", 403 | options->app_options.hwaccel_output_format); 404 | config_save_file.WriteFormated(CONFIG_APP_OPTIONS_AUTOROTATE_FIELD "=%s\n", 405 | common::ConvertToString(options->app_options.autorotate)); 406 | 407 | config_save_file.Write("[" CONFIG_PLAYER_OPTIONS "]\n"); 408 | config_save_file.WriteFormated(CONFIG_PLAYER_OPTIONS_WIDTH_FIELD "=%d\n", 409 | options->player_options.screen_size.width()); 410 | config_save_file.WriteFormated(CONFIG_PLAYER_OPTIONS_HEIGHT_FIELD "=%d\n", 411 | options->player_options.screen_size.height()); 412 | config_save_file.WriteFormated(CONFIG_PLAYER_OPTIONS_FULLSCREEN_FIELD "=%s\n", 413 | common::ConvertToString(options->player_options.is_full_screen)); 414 | config_save_file.WriteFormated(CONFIG_PLAYER_OPTIONS_VOLUME_FIELD "=%d\n", options->player_options.audio_volume); 415 | config_save_file.WriteFormated(CONFIG_PLAYER_OPTIONS_LAST_SHOWED_CHANNEL_ID_FIELD "=%s\n", 416 | options->player_options.last_showed_channel_id); 417 | return common::ErrnoError(); 418 | } 419 | } // namespace client 420 | } // namespace fastotv 421 | -------------------------------------------------------------------------------- /src/client/load_config.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | #include // for Error 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | namespace fastotv { 31 | namespace client { 32 | 33 | struct FastoTVConfig : public fastoplayer::TVConfig { 34 | commands_info::AuthInfo auth_options; 35 | common::net::HostAndPort server; 36 | }; 37 | 38 | common::ErrnoError load_config_file(const std::string& config_absolute_path, FastoTVConfig* options) WARN_UNUSED_RESULT; 39 | common::ErrnoError save_config_file(const std::string& config_absolute_path, FastoTVConfig* options) WARN_UNUSED_RESULT; 40 | 41 | } // namespace client 42 | } // namespace fastotv 43 | -------------------------------------------------------------------------------- /src/client/player.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "client/events/network_events.h" // for BandwidthEstimationEvent 27 | #include "client/live_stream/playlist_entry.h" 28 | 29 | namespace fastoplayer { 30 | namespace gui { 31 | class IconLabel; 32 | class Button; 33 | } // namespace gui 34 | } // namespace fastoplayer 35 | 36 | namespace fastotv { 37 | namespace client { 38 | 39 | class IoService; 40 | class ChatWindow; 41 | class ProgramsWindow; 42 | 43 | class Player : public fastoplayer::ISimplePlayer { 44 | public: 45 | static const SDL_Color failed_color; 46 | static const SDL_Color playlist_color; 47 | static const SDL_Color info_channel_color; 48 | static const SDL_Color chat_color; 49 | static const SDL_Color keypad_color; 50 | static const SDL_Color playlist_item_preselect_color; 51 | 52 | typedef fastoplayer::ISimplePlayer base_class; 53 | enum { footer_height = 60, keypad_height = 30, keypad_width = 60, min_key_pad_size = 0, max_keypad_size = 999 }; 54 | Player(const std::string& app_directory_absolute_path, // for runtime data (cache) 55 | const common::net::HostAndPort& server, 56 | const commands_info::AuthInfo& ainf, 57 | const fastoplayer::PlayerOptions& options, 58 | const fastoplayer::media::AppOptions& opt, 59 | const fastoplayer::media::ComplexOptions& copt); 60 | 61 | ~Player() override; 62 | 63 | std::string GetCurrentUrlName() const override; // return Unknown if not found 64 | fastoplayer::media::AppOptions GetStreamOptions() const; 65 | 66 | protected: 67 | void HandleEvent(event_t* event) override; 68 | void HandleExceptionEvent(event_t* event, common::Error err) override; 69 | 70 | void HandlePreExecEvent(fastoplayer::gui::events::PreExecEvent* event) override; 71 | void HandlePostExecEvent(fastoplayer::gui::events::PostExecEvent* event) override; 72 | 73 | void HandleTimerEvent(fastoplayer::gui::events::TimerEvent* event) override; 74 | 75 | virtual void HandleClientServerInfoEvent(events::ClientServerInfoEvent* event); 76 | virtual void HandleClientConnectedEvent(events::ClientConnectedEvent* event); 77 | virtual void HandleClientDisconnectedEvent(events::ClientDisconnectedEvent* event); 78 | virtual void HandleClientAuthorizedEvent(events::ClientAuthorizedEvent* event); 79 | virtual void HandleClientUnAuthorizedEvent(events::ClientUnAuthorizedEvent* event); 80 | virtual void HandleClientConfigChangeEvent(events::ClientConfigChangeEvent* event); 81 | virtual void HandleReceiveChannelsEvent(events::ReceiveChannelsEvent* event); 82 | virtual void HandleReceiveRuntimeChannelEvent(events::ReceiveRuntimeChannelEvent* event); 83 | virtual void HandleNotificationTextEvent(events::NotificationTextEvent* event); 84 | virtual void HandleNotificationShutdownEvent(events::NotificationShutdownEvent *event); 85 | 86 | void HandleKeyPressEvent(fastoplayer::gui::events::KeyPressEvent* event) override; 87 | void HandleLircPressEvent(fastoplayer::gui::events::LircPressEvent* event) override; 88 | 89 | void DrawInfo() override; 90 | void DrawFailedStatus() override; 91 | void DrawInitStatus() override; 92 | 93 | void InitWindow(const std::string& title, States status) override; 94 | void SetStatus(States new_state) override; 95 | 96 | fastoplayer::media::VideoState* CreateStream(stream_id_t sid, 97 | const common::uri::GURL& uri, 98 | fastoplayer::media::AppOptions opt, 99 | fastoplayer::media::ComplexOptions copt) override; 100 | 101 | void OnWindowCreated(SDL_Window* window, SDL_Renderer* render) override; 102 | 103 | private: 104 | void LoadChannelIcon(const PlaylistEntry& entry); 105 | 106 | typedef fastotv::commands_info::NotificationTextInfo::MessageType admin_message_type_t; 107 | void SetVisiblePlaylist(bool visible); 108 | 109 | bool GetChannelDescription(size_t pos, ChannelDescription* descr) const; 110 | bool GetChannelWatchers(size_t* watchers) const; 111 | 112 | void HandleKeyPad(uint8_t key); 113 | void FinishKeyPadInput(); 114 | void RemoveLastSymbolInKeypad(); 115 | void CreateStreamPosAfterKeypad(size_t pos); 116 | void ResetKeyPad(); 117 | SDL_Rect GetKeyPadRect() const; 118 | 119 | void DrawFooter(); 120 | void DrawKeyPad(); 121 | void DrawProgramsList(); 122 | void DrawWatchers(); 123 | void DrawAdminMessage(); 124 | 125 | void StartShowFooter(); 126 | SDL_Rect GetFooterRect() const; 127 | 128 | void StartShowAdminMessage(const std::string& text, admin_message_type_t type, fastoplayer::media::msec_t ttl); 129 | SDL_Rect GetAdminRect() const; 130 | 131 | SDL_Rect GetWatcherRect() const; 132 | 133 | void ToggleShowProgramsList(); 134 | SDL_Rect GetProgramsListRect() const; 135 | SDL_Rect GetHideButtonPlayListRect() const; 136 | SDL_Rect GetShowButtonPlayListRect() const; 137 | 138 | bool GetCurrentUrl(PlaylistEntry* url) const; 139 | 140 | void SwitchToPlayingMode(); 141 | void SwitchToConnectMode(); 142 | void SwitchToDisconnectMode(); 143 | void SwitchToDisconnectModeCheckConfig(); 144 | void SwitchToAuthorizeMode(); 145 | void SwitchToUnAuthorizeMode(); 146 | 147 | fastoplayer::media::VideoState* CreateNextStream(); 148 | fastoplayer::media::VideoState* CreatePrevStream(); 149 | fastoplayer::media::VideoState* CreateStreamPos(size_t pos); 150 | 151 | size_t GenerateNextPosition() const; 152 | size_t GeneratePrevPosition() const; 153 | 154 | void MoveToNextStream(); 155 | void MoveToPreviousStream(); 156 | 157 | fastoplayer::draw::SurfaceSaver* offline_channel_texture_; 158 | fastoplayer::draw::SurfaceSaver* connection_error_texture_; 159 | 160 | fastoplayer::draw::SurfaceSaver* right_arrow_button_texture_; 161 | fastoplayer::draw::SurfaceSaver* left_arrow_button_texture_; 162 | 163 | fastoplayer::gui::Button* show_playlist_button_; 164 | fastoplayer::gui::Button* hide_playlist_button_; 165 | 166 | IoService* controller_; 167 | 168 | size_t current_stream_pos_; 169 | std::vector play_list_; 170 | 171 | fastoplayer::gui::IconLabel* description_label_; 172 | fastoplayer::media::msec_t footer_last_shown_; 173 | 174 | fastoplayer::gui::IconLabel* admin_label_; 175 | admin_message_type_t admin_label_type_; 176 | fastoplayer::media::msec_t admin_last_shown_; 177 | fastoplayer::media::msec_t admin_show_time_; 178 | 179 | const fastoplayer::media::AppOptions opt_; 180 | const fastoplayer::media::ComplexOptions copt_; 181 | 182 | const std::string app_directory_absolute_path_; 183 | 184 | fastoplayer::gui::Label* keypad_label_; 185 | fastoplayer::media::msec_t keypad_last_shown_; 186 | 187 | ProgramsWindow* programs_window_; 188 | 189 | commands_info::AuthInfo auth_; 190 | }; 191 | 192 | } // namespace client 193 | } // namespace fastotv 194 | -------------------------------------------------------------------------------- /src/client/programs_window.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/programs_window.h" 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include "client/live_stream/playlist_window.h" 26 | 27 | #define SEARCH_PLACEHOLDER "Search..." 28 | 29 | namespace fastotv { 30 | namespace client { 31 | 32 | const SDL_Color ProgramsWindow::text_background_color = fastoplayer::draw::white_color; 33 | 34 | ProgramsWindow::ProgramsWindow(const SDL_Color& back_ground_color) 35 | : base_class(), 36 | plailist_window_(nullptr), 37 | text_input_box_(nullptr), 38 | font_(nullptr), 39 | text_color_(), 40 | proxy_clicked_cb_(), 41 | origin_(nullptr), 42 | filtered_origin_() { 43 | SetTransparent(true); 44 | 45 | // playlist window 46 | plailist_window_ = new PlaylistWindow(back_ground_color, this); 47 | plailist_window_->SetVisible(true); 48 | plailist_window_->SetPlaylist(&filtered_origin_); 49 | 50 | text_input_box_ = new fastoplayer::gui::LineEdit(text_background_color, this); 51 | text_input_box_->SetTextColor(fastoplayer::draw::black_color); 52 | text_input_box_->SetDrawType(fastoplayer::gui::Label::WRAPPED_TEXT); 53 | text_input_box_->SetVisible(true); 54 | text_input_box_->SetBorderColor(fastoplayer::draw::black_color); 55 | text_input_box_->SetBordered(true); 56 | text_input_box_->SetEnabled(true); 57 | text_input_box_->SetPlaceHolder(SEARCH_PLACEHOLDER); 58 | auto search_text_changed_cb = [this](const std::string& text) { 59 | filtered_origin_.clear(); 60 | if (!origin_) { 61 | return; 62 | } 63 | 64 | for (size_t i = 0; i < origin_->size(); ++i) { 65 | PlaylistEntry ent = origin_->operator[](i); 66 | commands_info::ChannelInfo cinf = ent.GetChannelInfo(); 67 | const commands_info::EpgInfo epg = cinf.GetEpg(); 68 | std::string name = epg.GetDisplayName(); 69 | if (text.empty() || name.find(text) != std::string::npos) { 70 | filtered_origin_.push_back(ent); 71 | } 72 | } 73 | }; 74 | text_input_box_->SetTextChangedCallback(search_text_changed_cb); 75 | 76 | auto mouse_clicked_cb = [this](Uint8 button, size_t row) { 77 | if (proxy_clicked_cb_) { 78 | if (!origin_) { 79 | return; 80 | } 81 | 82 | PlaylistEntry ent = filtered_origin_[row]; 83 | commands_info::ChannelInfo ent_inf = ent.GetChannelInfo(); 84 | for (size_t i = 0; i < origin_->size(); ++i) { 85 | PlaylistEntry cent = origin_->operator[](i); 86 | if (cent.GetChannelInfo() == ent_inf) { 87 | proxy_clicked_cb_(button, i); 88 | return; 89 | } 90 | } 91 | } 92 | }; 93 | plailist_window_->SetMouseClickedRowCallback(mouse_clicked_cb); 94 | } 95 | 96 | ProgramsWindow::~ProgramsWindow() { 97 | destroy(&text_input_box_); 98 | destroy(&plailist_window_); 99 | } 100 | 101 | bool ProgramsWindow::IsActived() const { 102 | return text_input_box_->IsActived(); 103 | } 104 | 105 | void ProgramsWindow::SetPlaylist(const PlaylistWindow::playlist_t* pl) { 106 | origin_ = pl; 107 | text_input_box_->ClearText(); 108 | } 109 | 110 | void ProgramsWindow::SetTextColor(const SDL_Color& color) { 111 | plailist_window_->SetTextColor(color); 112 | text_color_ = color; 113 | } 114 | 115 | void ProgramsWindow::SetSelection(PlaylistWindow::Selection sel) { 116 | plailist_window_->SetSelection(sel); 117 | } 118 | 119 | void ProgramsWindow::SetFont(TTF_Font* font) { 120 | plailist_window_->SetFont(font); 121 | text_input_box_->SetFont(font); 122 | font_ = font; 123 | } 124 | 125 | void ProgramsWindow::SetRowHeight(int row_height) { 126 | plailist_window_->SetRowHeight(row_height); 127 | } 128 | 129 | void ProgramsWindow::SetSelectionColor(const SDL_Color& sel) { 130 | plailist_window_->SetSelectionColor(sel); 131 | } 132 | 133 | void ProgramsWindow::SetDrawType(fastoplayer::gui::FontWindow::DrawType dt) { 134 | plailist_window_->SetDrawType(dt); 135 | } 136 | 137 | void ProgramsWindow::SetCurrentPositionSelectionColor(const SDL_Color& sel) { 138 | plailist_window_->SetActiveRowColor(sel); 139 | } 140 | 141 | void ProgramsWindow::SetCurrentPositionInPlaylist(size_t pos) { 142 | plailist_window_->SetActiveRow(pos); 143 | } 144 | 145 | void ProgramsWindow::SetMouseClickedRowCallback(PlaylistWindow::mouse_clicked_row_callback_t cb) { 146 | proxy_clicked_cb_ = cb; 147 | } 148 | 149 | void ProgramsWindow::Draw(SDL_Renderer* render) { 150 | if (!IsCanDraw()) { 151 | base_class::Draw(render); 152 | return; 153 | } 154 | 155 | base_class::Draw(render); 156 | 157 | plailist_window_->SetRect(GetPlaylistRect()); 158 | plailist_window_->Draw(render); 159 | 160 | text_input_box_->SetRect(GetTextInputRect()); 161 | text_input_box_->Draw(render); 162 | } 163 | 164 | SDL_Rect ProgramsWindow::GetPlaylistRect() const { 165 | if (!font_) { 166 | return fastoplayer::draw::empty_rect; 167 | } 168 | 169 | int font_height_2line = fastoplayer::draw::CalcHeightFontPlaceByRowCount(font_, 1); 170 | SDL_Rect chat_rect = GetRect(); 171 | int button_height = font_height_2line; 172 | SDL_Rect chat_rect_without_filter_rect = {chat_rect.x, chat_rect.y, chat_rect.w, chat_rect.h - button_height}; 173 | return chat_rect_without_filter_rect; 174 | } 175 | 176 | SDL_Rect ProgramsWindow::GetTextInputRect() const { 177 | if (!font_) { 178 | return fastoplayer::draw::empty_rect; 179 | } 180 | 181 | int font_height_2line = fastoplayer::draw::CalcHeightFontPlaceByRowCount(font_, 1); 182 | SDL_Rect chat_rect = GetRect(); 183 | SDL_Rect text_input_rect = {chat_rect.x, chat_rect.y + chat_rect.h - font_height_2line, chat_rect.w, 184 | font_height_2line}; 185 | return text_input_rect; 186 | } 187 | 188 | } // namespace client 189 | } // namespace fastotv 190 | -------------------------------------------------------------------------------- /src/client/programs_window.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | #include "client/live_stream/playlist_window.h" 24 | 25 | namespace fastoplayer { 26 | namespace gui { 27 | class Button; 28 | class LineEdit; 29 | } // namespace gui 30 | } // namespace fastoplayer 31 | 32 | namespace fastotv { 33 | namespace client { 34 | 35 | class ProgramsWindow : public fastoplayer::gui::Window { 36 | public: 37 | typedef fastoplayer::gui::Window base_class; 38 | static const SDL_Color text_background_color; 39 | 40 | explicit ProgramsWindow(const SDL_Color& back_ground_color); 41 | ~ProgramsWindow() override; 42 | 43 | bool IsActived() const; 44 | 45 | void SetMouseClickedRowCallback(PlaylistWindow::mouse_clicked_row_callback_t cb); 46 | 47 | void SetPlaylist(const PlaylistWindow::playlist_t* pl); 48 | 49 | void SetTextColor(const SDL_Color& color); 50 | 51 | void SetSelection(PlaylistWindow::Selection sel); 52 | 53 | void SetFont(TTF_Font* font); 54 | 55 | void SetRowHeight(int row_height); 56 | 57 | void SetSelectionColor(const SDL_Color& sel); 58 | 59 | void SetDrawType(fastoplayer::gui::FontWindow::DrawType dt); 60 | 61 | void SetCurrentPositionSelectionColor(const SDL_Color& sel); 62 | 63 | void SetCurrentPositionInPlaylist(size_t pos); 64 | 65 | void Draw(SDL_Renderer* render) override; 66 | 67 | private: 68 | SDL_Rect GetPlaylistRect() const; 69 | SDL_Rect GetTextInputRect() const; 70 | 71 | PlaylistWindow* plailist_window_; 72 | fastoplayer::gui::LineEdit* text_input_box_; 73 | 74 | TTF_Font* font_; 75 | SDL_Color text_color_; 76 | // filters 77 | PlaylistWindow::mouse_clicked_row_callback_t proxy_clicked_cb_; 78 | const PlaylistWindow::playlist_t* origin_; 79 | PlaylistWindow::playlist_t filtered_origin_; 80 | }; 81 | 82 | } // namespace client 83 | } // namespace fastotv 84 | -------------------------------------------------------------------------------- /src/client/tv_player_main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | extern "C" { 24 | #include // for avdevice_register_all 25 | #include // for avfilter_register_all 26 | } 27 | 28 | #include // for File, create_directory 29 | #include // for File, create_directory 30 | #include 31 | 32 | #include 33 | 34 | #include "client/cmdutils.h" // for DictionaryOptions, show_... 35 | #include "client/load_config.h" 36 | #include "client/player.h" // for Player 37 | 38 | void init_ffmpeg() { 39 | /* register all codecs, demux and protocols */ 40 | #if CONFIG_AVDEVICE 41 | avdevice_register_all(); 42 | #endif 43 | avformat_network_init(); 44 | } 45 | 46 | int main_application(int argc, char** argv, const std::string& app_directory_absolute_path) { 47 | int res = fastoplayer::prepare_to_start(app_directory_absolute_path); 48 | if (res == EXIT_FAILURE) { 49 | return EXIT_FAILURE; 50 | } 51 | 52 | const std::string config_absolute_path = 53 | common::file_system::make_path(app_directory_absolute_path, CONFIG_FILE_NAME); 54 | if (!common::file_system::is_valid_path(config_absolute_path)) { 55 | std::cout << "Invalid config file path: " << config_absolute_path << std::endl; 56 | return EXIT_FAILURE; 57 | } 58 | 59 | fastotv::client::FastoTVConfig main_options; 60 | common::ErrnoError err = fastotv::client::load_config_file(config_absolute_path, &main_options); 61 | if (err) { 62 | return EXIT_FAILURE; 63 | } 64 | 65 | #if defined(LOG_TO_FILE) 66 | const std::string log_path = common::file_system::make_path(app_directory_absolute_path, std::string(LOG_FILE_NAME)); 67 | INIT_LOGGER(PROJECT_NAME_TITLE, log_path, main_options.loglevel); 68 | #else 69 | INIT_LOGGER(PROJECT_NAME_TITLE, main_options.loglevel); 70 | #endif 71 | 72 | fastoplayer::FFmpegApplication app(argc, argv); 73 | 74 | AVDictionary* sws_dict = nullptr; 75 | AVDictionary* swr_opts = nullptr; 76 | AVDictionary* format_opts = nullptr; 77 | AVDictionary* codec_opts = nullptr; 78 | av_dict_set(&sws_dict, "flags", "bicubic", 0); 79 | 80 | fastoplayer::media::ComplexOptions copt(swr_opts, sws_dict, format_opts, codec_opts); 81 | auto player = new fastotv::client::Player(app_directory_absolute_path, main_options.server, main_options.auth_options, 82 | main_options.player_options, main_options.app_options, copt); 83 | res = app.Exec(); 84 | main_options.player_options = player->GetOptions(); 85 | destroy(&player); 86 | 87 | av_dict_free(&swr_opts); 88 | av_dict_free(&sws_dict); 89 | av_dict_free(&format_opts); 90 | av_dict_free(&codec_opts); 91 | 92 | // save config file 93 | err = fastotv::client::save_config_file(config_absolute_path, &main_options); 94 | if (main_options.power_off_on_exit) { 95 | common::ErrnoError err_shut = common::system::Shutdown(common::system::SHUTDOWN); 96 | if (err_shut) { 97 | WARNING_LOG() << "Can't shutdown error: " << err_shut->GetDescription(); 98 | } 99 | } 100 | return res; 101 | } 102 | 103 | /* Called from the main */ 104 | int main(int argc, char** argv) { 105 | init_ffmpeg(); 106 | 107 | for (int i = 1; i < argc; ++i) { 108 | const bool lastarg = i == argc - 1; 109 | if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { 110 | show_version(); 111 | return EXIT_SUCCESS; 112 | } else if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0) { 113 | std::string topic; 114 | if (!lastarg) { 115 | topic = argv[++i]; 116 | } 117 | show_help_tv_player(topic); 118 | return EXIT_SUCCESS; 119 | } else if (strcmp(argv[i], "-license") == 0 || strcmp(argv[i], "-l") == 0) { 120 | show_license(); 121 | return EXIT_SUCCESS; 122 | } else if (strcmp(argv[i], "-buildconf") == 0) { 123 | show_buildconf(); 124 | return EXIT_SUCCESS; 125 | } else if (strcmp(argv[i], "-formats") == 0) { 126 | show_formats(); 127 | return EXIT_SUCCESS; 128 | } else if (strcmp(argv[i], "-devices") == 0) { 129 | show_devices(); 130 | return EXIT_SUCCESS; 131 | } else if (strcmp(argv[i], "-muxers") == 0) { 132 | show_muxers(); 133 | return EXIT_SUCCESS; 134 | } else if (strcmp(argv[i], "-demuxers") == 0) { 135 | show_demuxers(); 136 | return EXIT_SUCCESS; 137 | } else if (strcmp(argv[i], "-codecs") == 0) { 138 | show_codecs(); 139 | return EXIT_SUCCESS; 140 | } else if (strcmp(argv[i], "-hwaccels") == 0) { 141 | show_hwaccels(); 142 | return EXIT_SUCCESS; 143 | } else if (strcmp(argv[i], "-decoders") == 0) { 144 | show_decoders(); 145 | return EXIT_SUCCESS; 146 | } else if (strcmp(argv[i], "-encoders") == 0) { 147 | show_encoders(); 148 | return EXIT_SUCCESS; 149 | } else if (strcmp(argv[i], "-bsfs") == 0) { 150 | show_bsfs(); 151 | return EXIT_SUCCESS; 152 | } else if (strcmp(argv[i], "-protocols") == 0) { 153 | show_protocols(); 154 | return EXIT_SUCCESS; 155 | } else if (strcmp(argv[i], "-filters") == 0) { 156 | show_filters(); 157 | return EXIT_SUCCESS; 158 | } else if (strcmp(argv[i], "-pix_fmts") == 0) { 159 | show_pix_fmts(); 160 | return EXIT_SUCCESS; 161 | } else if (strcmp(argv[i], "-layouts") == 0) { 162 | show_layouts(); 163 | return EXIT_SUCCESS; 164 | } else if (strcmp(argv[i], "-sample_fmts") == 0) { 165 | show_sample_fmts(); 166 | return EXIT_SUCCESS; 167 | } else if (strcmp(argv[i], "-colors") == 0) { 168 | show_colors(); 169 | return EXIT_SUCCESS; 170 | } 171 | #if CONFIG_AVDEVICE 172 | else if (strcmp(argv[i], "-sources") == 0) { 173 | std::string device; 174 | if (!lastarg) { 175 | device = argv[++i]; 176 | } 177 | show_sources(device); 178 | return EXIT_SUCCESS; 179 | } else if (strcmp(argv[i], "-sinks") == 0) { 180 | std::string device; 181 | if (!lastarg) { 182 | device = argv[++i]; 183 | } 184 | show_sinks(device); 185 | return EXIT_SUCCESS; 186 | } 187 | #endif 188 | else { 189 | show_help_tv_player(std::string()); 190 | return EXIT_SUCCESS; 191 | } 192 | } 193 | 194 | const std::string app_directory_path = APPLICATION_DIR; 195 | const bool is_abs = common::file_system::is_absolute_path(app_directory_path); 196 | const std::string app_directory_absolute_path = 197 | is_abs ? app_directory_path : common::file_system::absolute_path_from_relative(app_directory_path); 198 | return main_application(argc, argv, app_directory_absolute_path); 199 | } 200 | -------------------------------------------------------------------------------- /src/client/utils.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/utils.h" 20 | 21 | #include 22 | 23 | extern "C" { 24 | #include 25 | } 26 | 27 | #include 28 | 29 | namespace fastotv { 30 | namespace client { 31 | namespace { 32 | class CallbackHolder { 33 | public: 34 | explicit CallbackHolder(quit_callback_t cb) : is_quit(cb) {} 35 | static int download_interrupt_callback(void* user_data) { 36 | CallbackHolder* holder = static_cast(user_data); 37 | if (holder->is_quit()) { 38 | return 1; 39 | } 40 | 41 | return 0; 42 | } 43 | 44 | private: 45 | const quit_callback_t is_quit; 46 | }; 47 | } // namespace 48 | 49 | bool DownloadFileToBuffer(const common::uri::GURL& uri, common::char_buffer_t* buff, quit_callback_t cb) { 50 | if (!uri.is_valid() || !buff || !cb) { 51 | return false; 52 | } 53 | 54 | const std::string url_str = fastoplayer::media::make_url(uri); 55 | if (url_str.empty()) { 56 | return false; 57 | } 58 | 59 | AVFormatContext* ic = avformat_alloc_context(); 60 | if (!ic) { 61 | return false; 62 | } 63 | 64 | const char* in_filename = url_str.c_str(); 65 | CallbackHolder holder(cb); 66 | ic->interrupt_callback.callback = CallbackHolder::download_interrupt_callback; 67 | ic->interrupt_callback.opaque = &holder; 68 | int open_result = avformat_open_input(&ic, in_filename, nullptr, nullptr); 69 | if (open_result < 0) { 70 | avformat_free_context(ic); 71 | ic = nullptr; 72 | return false; 73 | } 74 | AVPacket pkt; 75 | int ret = av_read_frame(ic, &pkt); 76 | if (ret < 0) { 77 | avformat_free_context(ic); 78 | ic = nullptr; 79 | return false; 80 | } 81 | 82 | *buff = common::char_buffer_t(pkt.data, pkt.data + pkt.size); 83 | av_packet_unref(&pkt); 84 | avformat_free_context(ic); 85 | ic = nullptr; 86 | return true; 87 | } 88 | 89 | } // namespace client 90 | } // namespace fastotv 91 | -------------------------------------------------------------------------------- /src/client/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | namespace fastotv { 27 | namespace client { 28 | 29 | typedef std::function quit_callback_t; 30 | bool DownloadFileToBuffer(const common::uri::GURL& uri, common::char_buffer_t* buff, quit_callback_t cb); 31 | 32 | } // namespace client 33 | } // namespace fastotv 34 | -------------------------------------------------------------------------------- /src/client/vod/vod_entry.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/vod/vod_entry.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #define IMG_UNKNOWN_CHANNEL_PATH_RELATIVE "share/resources/unknown_channel.png" 27 | 28 | #define ICON_FILE_NAME "icon" 29 | 30 | namespace fastotv { 31 | namespace client { 32 | 33 | VodEntry::VodEntry() : info_(), icon_(), cache_dir_() {} 34 | 35 | VodEntry::VodEntry(const std::string& cache_root_dir, const commands_info::VodInfo& info) 36 | : info_(info), rinfo_(), icon_(), cache_dir_() { 37 | stream_id_t id = info_.GetStreamID(); 38 | cache_dir_ = common::file_system::make_path(cache_root_dir, id); 39 | } 40 | 41 | std::string VodEntry::GetCacheDir() const { 42 | return cache_dir_; 43 | } 44 | 45 | std::string VodEntry::GetIconPath() const { 46 | commands_info::MovieInfo movie = info_.GetMovieInfo(); 47 | common::uri::GURL uri = movie.GetPreviewIcon(); 48 | bool is_unknown_icon = uri == "https://fastocloud.com/images/unknown_channel.png"; 49 | if (is_unknown_icon) { 50 | const std::string absolute_source_dir = 51 | common::file_system::absolute_path_from_relative(RELATIVE_SOURCE_DIR, common::file_system::app_pwd()); // + 52 | return common::file_system::make_path(absolute_source_dir, IMG_UNKNOWN_CHANNEL_PATH_RELATIVE); 53 | } 54 | std::string dir = GetCacheDir(); 55 | return common::file_system::make_path(dir, ICON_FILE_NAME); 56 | } 57 | 58 | VodDescription VodEntry::GetChannelDescription() const { 59 | std::string decr = "N/A"; 60 | commands_info::VodInfo url = GetVodInfo(); 61 | commands_info::MovieInfo movie = url.GetMovieInfo(); 62 | std::string descr_str = movie.GetDescription(); 63 | if (!descr_str.empty()) { 64 | decr = descr_str; 65 | } 66 | 67 | return {movie.GetName(), decr, GetIcon()}; 68 | } 69 | 70 | void VodEntry::SetIcon(channel_icon_t icon) { 71 | icon_ = icon; 72 | } 73 | 74 | channel_icon_t VodEntry::GetIcon() const { 75 | return icon_; 76 | } 77 | 78 | commands_info::VodInfo VodEntry::GetVodInfo() const { 79 | return info_; 80 | } 81 | 82 | void VodEntry::SetRuntimeChannelInfo(const commands_info::RuntimeChannelInfo& rinfo) { 83 | rinfo_ = rinfo; 84 | } 85 | 86 | commands_info::RuntimeChannelInfo VodEntry::GetRuntimeChannelInfo() const { 87 | return rinfo_; 88 | } 89 | 90 | } // namespace client 91 | } // namespace fastotv 92 | -------------------------------------------------------------------------------- /src/client/vod/vod_entry.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | namespace fastoplayer { 28 | namespace draw { 29 | class SurfaceSaver; 30 | } 31 | } // namespace fastoplayer 32 | 33 | namespace fastotv { 34 | namespace client { 35 | 36 | typedef std::shared_ptr channel_icon_t; 37 | 38 | struct VodDescription { 39 | std::string title; 40 | std::string description; 41 | channel_icon_t icon; 42 | }; 43 | 44 | class VodEntry { 45 | public: 46 | VodEntry(); 47 | VodEntry(const std::string& cache_root_dir, const commands_info::VodInfo& info); 48 | 49 | commands_info::VodInfo GetVodInfo() const; 50 | 51 | void SetRuntimeChannelInfo(const commands_info::RuntimeChannelInfo& rinfo); 52 | commands_info::RuntimeChannelInfo GetRuntimeChannelInfo() const; 53 | 54 | void SetIcon(channel_icon_t icon); 55 | channel_icon_t GetIcon() const; 56 | 57 | std::string GetCacheDir() const; 58 | std::string GetIconPath() const; 59 | 60 | VodDescription GetChannelDescription() const; 61 | 62 | private: 63 | commands_info::VodInfo info_; 64 | commands_info::RuntimeChannelInfo rinfo_; 65 | 66 | channel_icon_t icon_; 67 | std::string cache_dir_; 68 | }; 69 | 70 | } // namespace client 71 | } // namespace fastotv 72 | -------------------------------------------------------------------------------- /src/client/vod/vods_window.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/vod/vods_window.h" 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | namespace fastotv { 32 | namespace client { 33 | 34 | VodsWindow::VodsWindow(const SDL_Color& back_ground_color, Window* parent) 35 | : base_class(back_ground_color, parent), play_list_(nullptr) {} 36 | 37 | VodsWindow::~VodsWindow() {} 38 | 39 | void VodsWindow::SetPlaylist(const playlist_t* pl) { 40 | play_list_ = pl; 41 | } 42 | 43 | const VodsWindow::playlist_t* VodsWindow::GetPlaylist() const { 44 | return play_list_; 45 | } 46 | 47 | size_t VodsWindow::GetRowCount() const { 48 | if (!play_list_) { 49 | return 0; 50 | } 51 | return play_list_->size(); 52 | } 53 | 54 | void VodsWindow::DrawRow(SDL_Renderer* render, size_t pos, bool active, bool hover, const SDL_Rect& row_rect) { 55 | UNUSED(active); 56 | UNUSED(hover); 57 | 58 | if (!play_list_) { 59 | return; 60 | } 61 | 62 | SDL_Rect number_rect = {row_rect.x, row_rect.y, channel_number_width, row_rect.h}; 63 | std::string number_str = common::ConvertToString(pos + 1); 64 | DrawText(render, number_str, number_rect, VodsWindow::CENTER_TEXT); 65 | 66 | VodDescription descr = play_list_->operator[](pos).GetChannelDescription(); 67 | channel_icon_t icon = descr.icon; 68 | int shift = channel_number_width; 69 | if (icon) { 70 | SDL_Texture* img = icon->GetTexture(render); 71 | if (img) { 72 | SDL_Rect icon_rect = {row_rect.x + shift, row_rect.y, row_rect.h, row_rect.h}; 73 | SDL_RenderCopy(render, img, nullptr, &icon_rect); 74 | } 75 | } 76 | shift += row_rect.h + space_width; // in any case shift should be 77 | 78 | int text_width = row_rect.w - shift; 79 | std::string title_line = 80 | fastoplayer::draw::DotText(common::MemSPrintf("Title: %s", descr.title), GetFont(), text_width); 81 | std::string description_line = 82 | fastoplayer::draw::DotText(common::MemSPrintf("Description: %s", descr.description), GetFont(), text_width); 83 | 84 | std::string line_text = common::MemSPrintf( 85 | "%s\n" 86 | "%s", 87 | title_line, description_line); 88 | SDL_Rect text_rect = {row_rect.x + shift, row_rect.y, text_width, row_rect.h}; 89 | DrawText(render, line_text, text_rect, GetDrawType()); 90 | } 91 | 92 | } // namespace client 93 | } // namespace fastotv 94 | -------------------------------------------------------------------------------- /src/client/vod/vods_window.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "client/vod/vod_entry.h" 27 | 28 | namespace fastotv { 29 | namespace client { 30 | 31 | class VodsWindow : public fastoplayer::gui::IListBox { 32 | public: 33 | typedef fastoplayer::gui::IListBox base_class; 34 | typedef std::vector playlist_t; 35 | enum { channel_number_width = 60, space_width = 10 }; 36 | explicit VodsWindow(const SDL_Color& back_ground_color, Window* parent = nullptr); 37 | ~VodsWindow() override; 38 | 39 | void SetPlaylist(const playlist_t* pl); 40 | const playlist_t* GetPlaylist() const; 41 | 42 | size_t GetRowCount() const override; 43 | 44 | protected: 45 | void DrawRow(SDL_Renderer* render, size_t pos, bool active, bool hover, const SDL_Rect& row_rect) override; 46 | 47 | private: 48 | const playlist_t* play_list_; // pointer 49 | }; 50 | 51 | } // namespace client 52 | } // namespace fastotv 53 | -------------------------------------------------------------------------------- /src/client/vods_window.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include "client/vods_window.h" 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include "client/live_stream/playlist_window.h" 26 | 27 | #define SEARCH_PLACEHOLDER "Search..." 28 | 29 | namespace fastotv { 30 | namespace client { 31 | 32 | const SDL_Color VodsListWindow::text_background_color = fastoplayer::draw::white_color; 33 | 34 | VodsListWindow::VodsListWindow(const SDL_Color& back_ground_color) 35 | : base_class(), 36 | plailist_window_(nullptr), 37 | text_input_box_(nullptr), 38 | font_(nullptr), 39 | text_color_(), 40 | proxy_clicked_cb_(), 41 | origin_(nullptr), 42 | filtered_origin_() { 43 | SetTransparent(true); 44 | 45 | // playlist window 46 | plailist_window_ = new VodsWindow(back_ground_color, this); 47 | plailist_window_->SetVisible(true); 48 | plailist_window_->SetPlaylist(&filtered_origin_); 49 | 50 | text_input_box_ = new fastoplayer::gui::LineEdit(text_background_color, this); 51 | text_input_box_->SetTextColor(fastoplayer::draw::black_color); 52 | text_input_box_->SetDrawType(fastoplayer::gui::Label::WRAPPED_TEXT); 53 | text_input_box_->SetVisible(true); 54 | text_input_box_->SetBorderColor(fastoplayer::draw::black_color); 55 | text_input_box_->SetBordered(true); 56 | text_input_box_->SetEnabled(true); 57 | text_input_box_->SetPlaceHolder(SEARCH_PLACEHOLDER); 58 | auto search_text_changed_cb = [this](const std::string& text) { 59 | filtered_origin_.clear(); 60 | if (!origin_) { 61 | return; 62 | } 63 | 64 | for (size_t i = 0; i < origin_->size(); ++i) { 65 | VodEntry ent = origin_->operator[](i); 66 | commands_info::VodInfo cinf = ent.GetVodInfo(); 67 | const commands_info::MovieInfo epg = cinf.GetMovieInfo(); 68 | std::string name = epg.GetName(); 69 | if (text.empty() || name.find(text) != std::string::npos) { 70 | filtered_origin_.push_back(ent); 71 | } 72 | } 73 | }; 74 | text_input_box_->SetTextChangedCallback(search_text_changed_cb); 75 | 76 | auto mouse_clicked_cb = [this](Uint8 button, size_t row) { 77 | if (proxy_clicked_cb_) { 78 | if (!origin_) { 79 | return; 80 | } 81 | 82 | VodEntry ent = filtered_origin_[row]; 83 | commands_info::VodInfo ent_inf = ent.GetVodInfo(); 84 | for (size_t i = 0; i < origin_->size(); ++i) { 85 | VodEntry cent = origin_->operator[](i); 86 | if (cent.GetVodInfo() == ent_inf) { 87 | proxy_clicked_cb_(button, i); 88 | return; 89 | } 90 | } 91 | } 92 | }; 93 | plailist_window_->SetMouseClickedRowCallback(mouse_clicked_cb); 94 | } 95 | 96 | VodsListWindow::~VodsListWindow() { 97 | destroy(&text_input_box_); 98 | destroy(&plailist_window_); 99 | } 100 | 101 | bool VodsListWindow::IsActived() const { 102 | return text_input_box_->IsActived(); 103 | } 104 | 105 | void VodsListWindow::SetPlaylist(const VodsWindow::playlist_t* pl) { 106 | origin_ = pl; 107 | text_input_box_->ClearText(); 108 | } 109 | 110 | void VodsListWindow::SetTextColor(const SDL_Color& color) { 111 | plailist_window_->SetTextColor(color); 112 | text_color_ = color; 113 | } 114 | 115 | void VodsListWindow::SetSelection(VodsWindow::Selection sel) { 116 | plailist_window_->SetSelection(sel); 117 | } 118 | 119 | void VodsListWindow::SetFont(TTF_Font* font) { 120 | plailist_window_->SetFont(font); 121 | text_input_box_->SetFont(font); 122 | font_ = font; 123 | } 124 | 125 | void VodsListWindow::SetRowHeight(int row_height) { 126 | plailist_window_->SetRowHeight(row_height); 127 | } 128 | 129 | void VodsListWindow::SetSelectionColor(const SDL_Color& sel) { 130 | plailist_window_->SetSelectionColor(sel); 131 | } 132 | 133 | void VodsListWindow::SetDrawType(fastoplayer::gui::FontWindow::DrawType dt) { 134 | plailist_window_->SetDrawType(dt); 135 | } 136 | 137 | void VodsListWindow::SetCurrentPositionSelectionColor(const SDL_Color& sel) { 138 | plailist_window_->SetActiveRowColor(sel); 139 | } 140 | 141 | void VodsListWindow::SetCurrentPositionInPlaylist(size_t pos) { 142 | plailist_window_->SetActiveRow(pos); 143 | } 144 | 145 | void VodsListWindow::SetMouseClickedRowCallback(VodsWindow::mouse_clicked_row_callback_t cb) { 146 | proxy_clicked_cb_ = cb; 147 | } 148 | 149 | void VodsListWindow::Draw(SDL_Renderer* render) { 150 | if (!IsCanDraw()) { 151 | base_class::Draw(render); 152 | return; 153 | } 154 | 155 | base_class::Draw(render); 156 | 157 | plailist_window_->SetRect(GetPlaylistRect()); 158 | plailist_window_->Draw(render); 159 | 160 | text_input_box_->SetRect(GetTextInputRect()); 161 | text_input_box_->Draw(render); 162 | } 163 | 164 | SDL_Rect VodsListWindow::GetPlaylistRect() const { 165 | if (!font_) { 166 | return fastoplayer::draw::empty_rect; 167 | } 168 | 169 | int font_height_2line = fastoplayer::draw::CalcHeightFontPlaceByRowCount(font_, 1); 170 | SDL_Rect chat_rect = GetRect(); 171 | int button_height = font_height_2line; 172 | SDL_Rect chat_rect_without_filter_rect = {chat_rect.x, chat_rect.y, chat_rect.w, chat_rect.h - button_height}; 173 | return chat_rect_without_filter_rect; 174 | } 175 | 176 | SDL_Rect VodsListWindow::GetTextInputRect() const { 177 | if (!font_) { 178 | return fastoplayer::draw::empty_rect; 179 | } 180 | 181 | int font_height_2line = fastoplayer::draw::CalcHeightFontPlaceByRowCount(font_, 1); 182 | SDL_Rect chat_rect = GetRect(); 183 | SDL_Rect text_input_rect = {chat_rect.x, chat_rect.y + chat_rect.h - font_height_2line, chat_rect.w, 184 | font_height_2line}; 185 | return text_input_rect; 186 | } 187 | 188 | } // namespace client 189 | } // namespace fastotv 190 | -------------------------------------------------------------------------------- /src/client/vods_window.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2022 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | #include "client/vod/vods_window.h" 24 | 25 | namespace fastoplayer { 26 | namespace gui { 27 | class Button; 28 | class LineEdit; 29 | } // namespace gui 30 | } // namespace fastoplayer 31 | 32 | namespace fastotv { 33 | namespace client { 34 | 35 | class VodsListWindow : public fastoplayer::gui::Window { 36 | public: 37 | typedef fastoplayer::gui::Window base_class; 38 | static const SDL_Color text_background_color; 39 | 40 | explicit VodsListWindow(const SDL_Color& back_ground_color); 41 | ~VodsListWindow() override; 42 | 43 | bool IsActived() const; 44 | 45 | void SetMouseClickedRowCallback(VodsWindow::mouse_clicked_row_callback_t cb); 46 | 47 | void SetPlaylist(const VodsWindow::playlist_t* pl); 48 | 49 | void SetTextColor(const SDL_Color& color); 50 | 51 | void SetSelection(VodsWindow::Selection sel); 52 | 53 | void SetFont(TTF_Font* font); 54 | 55 | void SetRowHeight(int row_height); 56 | 57 | void SetSelectionColor(const SDL_Color& sel); 58 | 59 | void SetDrawType(fastoplayer::gui::FontWindow::DrawType dt); 60 | 61 | void SetCurrentPositionSelectionColor(const SDL_Color& sel); 62 | 63 | void SetCurrentPositionInPlaylist(size_t pos); 64 | 65 | void Draw(SDL_Renderer* render) override; 66 | 67 | private: 68 | SDL_Rect GetPlaylistRect() const; 69 | SDL_Rect GetTextInputRect() const; 70 | 71 | VodsWindow* plailist_window_; 72 | fastoplayer::gui::LineEdit* text_input_box_; 73 | 74 | TTF_Font* font_; 75 | SDL_Color text_color_; 76 | // filters 77 | VodsWindow::mouse_clicked_row_callback_t proxy_clicked_cb_; 78 | const VodsWindow::playlist_t* origin_; 79 | VodsWindow::playlist_t filtered_origin_; 80 | }; 81 | 82 | } // namespace client 83 | } // namespace fastotv 84 | -------------------------------------------------------------------------------- /src/third-party/ini/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.3.0) 2 | PROJECT(inih C) 3 | 4 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/inih) 5 | 6 | SET(HEADERS_INIH 7 | inih/ini.h 8 | ) 9 | 10 | SET(SOURCES_INIH 11 | inih/ini.c 12 | ) 13 | 14 | SET(LIBS_INIH) 15 | 16 | ADD_LIBRARY(${PROJECT_NAME} STATIC ${HEADERS_INIH} ${SOURCES_INIH}) 17 | -------------------------------------------------------------------------------- /tests/unit_tests/test_commands.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014-2019 FastoGT. All right reserved. 2 | 3 | This file is part of FastoTV. 4 | 5 | FastoTV is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | FastoTV is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with FastoTV. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include "client/commands.h" 22 | 23 | TEST(Client, TestCommands) { 24 | const auto req = fastotv::client::GetChannelsRequest(std::string("11")); 25 | ASSERT_TRUE(req.IsValid()); 26 | } 27 | --------------------------------------------------------------------------------