diff --git a/.gitignore b/.gitignore
index bef0909..6f93296 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,10 @@
-/*.pro.user
-/mcc.json
-/youtube-data-api-v3.key
-/youtube-client-id.json
+*.pro.user*
+mcc.json
+youtube-data-api-v3*
+youtube-client-id*
+rpm/*.spec*
+src/config.h
+*.bak
+*.autosave
+scripts/version-str
+youtube-dl-lite
diff --git a/LICENSE.YTPlayer b/LICENSE.YTPlayer
index 4244002..de8a8da 100644
--- a/LICENSE.YTPlayer
+++ b/LICENSE.YTPlayer
@@ -1,4 +1,6 @@
Copyright (c) 2014-2015 Piotr Tworek
+Copyright (c) 2015-2018 Petr Tsymbarovich
+Copyright (c) 2019-2020 Matti Viljanen
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
diff --git a/README.md b/README.md
index ecc2e1e..d803518 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,11 @@ YTPlayer
YTPlayer is an unofficial YouTube client for SailfishOS.
Getting the source
@@ -14,7 +16,7 @@ Getting the source
Since YTPlayer uses some extra 3rd party components shipped in git submodules it needs to be cloned with --recursive option. Ex:
-- git clone --recursive https://github.com/tworaz/sailfish-ytplayer.git
+- git clone --recursive https://github.com/direc85/sailfish-ytplayer.git
Build Prequisites
-----------------
@@ -33,7 +35,25 @@ Building
4. Load harbour-ytplayer.pro file.
5. Build and deploy the application to your phone/tablet/emulator.
+If translations don't work, try the following:
+
+1. Select i486/armv7hl > Release > Deploy as ARM package
+2. Build > Clean project "harbour-ytplayer"
+3. Build > Build project "harbour-ytplayer" (or click the hammer icon)
+4. Build > Deploy project "harbour-ytplayer" (or click the play icon)
+
Translating
-----------
-If you want to translate YTPlayer into your native language you can use Transifex (https://www.transifex.com/tworaz/ytplayer).
+If you would like to create a new translation for YTPlayer, this is roughly how it's done:
+- Fork the project
+- Copy translations/en_GB.ts file to your language (e.g. no.ts for Norwgian)
+- Add the new file to translations/translations.pri files TRANSLATIONS section accordingly
+- Translate the new file
+ - Qt Linguist comes with Sailfish Application SDK
+ - Your generic UTF-8 capable text editor will work, too
+- Test the translation
+- Commit the changes
+- Make a pull request
+
+Or you can avoid forking by just creating a new issue and attach the new translated .ts file in the issue.
diff --git a/YTPlayer.qrc b/YTPlayer.qrc
index 9796c19..dfbb464 100644
--- a/YTPlayer.qrc
+++ b/YTPlayer.qrc
@@ -1,22 +1,35 @@
resources/mcc-data.json
- resources/logo.png
- languages/translations.json
+ translations/translations.json
+ harbour-ytplayer.png
+ artwork/Ko-fi_Icon_RGB_rounded.png
- resources/icons/approval-64.png
- resources/icons/dislike-m.png
- resources/icons/downloaded-videos-64.png
- resources/icons/like-m.png
- resources/icons/rss-m.png
- resources/icons/search-m.png
- resources/icons/video-multi-m.png
- resources/icons/categorize-64.png
- resources/icons/bookmark-2-64.png
- resources/icons/star-8-64.png
- resources/icons/play-64.png
- resources/icons/pause-64.png
+ resources/icons/approval-64-white.png
+ resources/icons/dislike-m-white.png
+ resources/icons/downloaded-videos-64-white.png
+ resources/icons/like-m-white.png
+ resources/icons/rss-m-white.png
+ resources/icons/search-m-white.png
+ resources/icons/video-multi-m-white.png
+ resources/icons/categorize-64-white.png
+ resources/icons/bookmark-2-64-white.png
+ resources/icons/star-8-64-white.png
+ resources/icons/play-64-white.png
+ resources/icons/pause-64-white.png
+ resources/icons/approval-64-black.png
+ resources/icons/dislike-m-black.png
+ resources/icons/downloaded-videos-64-black.png
+ resources/icons/like-m-black.png
+ resources/icons/rss-m-black.png
+ resources/icons/search-m-black.png
+ resources/icons/video-multi-m-black.png
+ resources/icons/categorize-64-black.png
+ resources/icons/bookmark-2-64-black.png
+ resources/icons/star-8-64-black.png
+ resources/icons/play-64-black.png
+ resources/icons/pause-64-black.png
resources/fonts/youtube-icons.ttf
@@ -41,6 +54,7 @@
qml/cover/VideoOverview.qml
qml/pages/About.qml
qml/pages/Account.qml
+ qml/pages/APIKeys.qml
qml/pages/CacheSettings.qml
qml/pages/CategoryVideoList.qml
qml/pages/ChannelBrowser.qml
diff --git a/artwork/Ko-fi_Icon_RGB_rounded.png b/artwork/Ko-fi_Icon_RGB_rounded.png
new file mode 100644
index 0000000..995171e
Binary files /dev/null and b/artwork/Ko-fi_Icon_RGB_rounded.png differ
diff --git a/artwork/icons/harbour-ytplayer-icon.svg b/artwork/icons/harbour-ytplayer-icon.svg
new file mode 100644
index 0000000..5db9666
--- /dev/null
+++ b/artwork/icons/harbour-ytplayer-icon.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/artwork/screenshots/20150915210645.jpg b/artwork/screenshots/20150915210645.jpg
deleted file mode 100644
index f26e81c..0000000
Binary files a/artwork/screenshots/20150915210645.jpg and /dev/null differ
diff --git a/artwork/screenshots/20150915210731.jpg b/artwork/screenshots/20150915210731.jpg
deleted file mode 100644
index 8d2f10f..0000000
Binary files a/artwork/screenshots/20150915210731.jpg and /dev/null differ
diff --git a/artwork/screenshots/20150915210805.jpg b/artwork/screenshots/20150915210805.jpg
deleted file mode 100644
index 355052a..0000000
Binary files a/artwork/screenshots/20150915210805.jpg and /dev/null differ
diff --git a/artwork/screenshots/VirtualBox_Sailfish OS Emulator_02_12_2018_00_53_48.png b/artwork/screenshots/VirtualBox_Sailfish OS Emulator_02_12_2018_00_53_48.png
new file mode 100644
index 0000000..9640625
Binary files /dev/null and b/artwork/screenshots/VirtualBox_Sailfish OS Emulator_02_12_2018_00_53_48.png differ
diff --git a/artwork/screenshots/VirtualBox_Sailfish OS Emulator_12_02_2019_15_00_00.png b/artwork/screenshots/VirtualBox_Sailfish OS Emulator_12_02_2019_15_00_00.png
new file mode 100644
index 0000000..bc10b58
Binary files /dev/null and b/artwork/screenshots/VirtualBox_Sailfish OS Emulator_12_02_2019_15_00_00.png differ
diff --git a/artwork/screenshots/VirtualBox_Sailfish OS Emulator_12_02_2019_15_00_45.png b/artwork/screenshots/VirtualBox_Sailfish OS Emulator_12_02_2019_15_00_45.png
new file mode 100644
index 0000000..1612c71
Binary files /dev/null and b/artwork/screenshots/VirtualBox_Sailfish OS Emulator_12_02_2019_15_00_45.png differ
diff --git a/harbour-ytplayer.png b/harbour-ytplayer.png
index f1965e2..bc824bb 100644
Binary files a/harbour-ytplayer.png and b/harbour-ytplayer.png differ
diff --git a/harbour-ytplayer.pro b/harbour-ytplayer.pro
index 53a9d94..03f599f 100644
--- a/harbour-ytplayer.pro
+++ b/harbour-ytplayer.pro
@@ -4,90 +4,81 @@
TARGET = harbour-ytplayer
-CONFIG += sailfishapp sailfishapp_no_deploy_qml
-QT += dbus sql concurrent
+CONFIG += sailfishapp sailfishapp_no_deploy_qml # sailfishapp_i18n
+
+PKGCONFIG += nemonotifications-qt5
+
+QT += dbus sql concurrent qml core multimedia
SOURCES += \
- src/YTPlayer.cpp \
- src/YTUtils.cpp \
- src/YTLogger.cpp \
- src/YTPrefs.cpp \
- src/YTRequest.cpp \
- src/YTListModel.cpp \
- src/YTNetworkManager.cpp \
- src/YTLocalVideo.cpp \
- src/YTLocalVideoData.cpp \
- src/YTLocalVideoManager.cpp \
- src/YTLocalVideoListModel.cpp \
- src/YTVideoDownloadNotification.cpp \
- src/YTVIdeoUrlFetcher.cpp \
- src/YTSuggestionEngine.cpp \
- src/YTTranslations.cpp \
- src/YTWatchedRecently.cpp \
- src/YTFavorites.cpp \
- src/YTSqlListModel.cpp
+ src/YTPlayer.cpp \
+ src/YTUtils.cpp \
+ src/YTLogger.cpp \
+ src/YTPrefs.cpp \
+ src/YTRequest.cpp \
+ src/YTListModel.cpp \
+ src/YTNetworkManager.cpp \
+ src/YTLocalVideo.cpp \
+ src/YTLocalVideoData.cpp \
+ src/YTLocalVideoManager.cpp \
+ src/YTLocalVideoListModel.cpp \
+ src/YTVideoDownloadNotification.cpp \
+ src/YTVIdeoUrlFetcher.cpp \
+ src/YTSuggestionEngine.cpp \
+ src/YTTranslations.cpp \
+ src/YTWatchedRecently.cpp \
+ src/YTFavorites.cpp \
+ src/YTSqlListModel.cpp \
+ src/YTUpdater.cpp \
+ src/YTUpdateWorker.cpp
HEADERS += \
- src/YTPlayer.h \
- src/YTUtils.h \
- src/YTLogger.h \
- src/YTPrefs.h \
- src/YTRequest.h \
- src/YTListModel.h \
- src/YTNetworkManager.h \
- src/YTLocalVideo.h \
- src/YTLocalVideoData.h \
- src/YTLocalVideoManager.h \
- src/YTLocalVideoListModel.h \
- src/YTVideoDownloadNotification.h \
- src/YTVideoUrlFetcher.h \
- src/YTSuggestionEngine.h \
- src/YTTranslations.h \
- src/YTWatchedRecently.h \
- src/YTFavorites.h \
- src/YTSqlListModel.h
+ src/YTPlayer.h \
+ src/YTUtils.h \
+ src/YTLogger.h \
+ src/YTPrefs.h \
+ src/YTRequest.h \
+ src/YTListModel.h \
+ src/YTNetworkManager.h \
+ src/YTLocalVideo.h \
+ src/YTLocalVideoData.h \
+ src/YTLocalVideoManager.h \
+ src/YTLocalVideoListModel.h \
+ src/YTVideoDownloadNotification.h \
+ src/YTVideoUrlFetcher.h \
+ src/YTSuggestionEngine.h \
+ src/YTTranslations.h \
+ src/YTWatchedRecently.h \
+ src/YTFavorites.h \
+ src/YTSqlListModel.h \
+ src/YTUpdater.h \
+ src/YTUpdateWorker.h
QML_SOURCES = \
- qml/*.qml \
- qml/pages/*.qml \
- qml/cover/*.qml \
- qml/common/*.qml \
- qml/common/*.js
+ qml/*.qml \
+ qml/pages/*.qml \
+ qml/cover/*.qml \
+ qml/common/*.qml \
+ qml/common/*.js
OTHER_FILES += \
- $$QML_SOURCES \
- harbour-ytplayer.desktop \
- scripts/mcc-data-util.py \
- scripts/generate-config-h.py \
- scripts/get_version_str.sh \
- rpm/harbour-ytplayer.spec
-
-include(third_party/youtube_dl.pri)
-include(languages/translations.pri)
-
-KEY_FILE = $$top_srcdir/youtube-data-api-v3.key
-CLIENT_ID_FILE = $$top_srcdir/youtube-client-id.json
+ $$QML_SOURCES \
+ harbour-ytplayer.desktop \
+ scripts/get_version_str.sh \
+ translations/*.ts
-!exists($$KEY_FILE) {
- error("YouTube data api key file not found: youtube-data-api-v3.key")
-}
-!exists($$CLIENT_ID_FILE) {
- warning("YouTube client ID file not found, client authotization won't work!")
-}
+DISTFILES += \
+ rpm/harbour-ytplayer.spec \
+ rpm/harbour-ytplayer.yaml \
+ translations/*.qm \
+ rpm/harbour-ytplayer.changes
-configh.input = KEY_FILE
-configh.output = $$top_builddir/config.h
-configh.commands = \
- $$top_srcdir/scripts/generate-config-h.py \
- --keyfile=$$KEY_FILE \
- --idfile=$$CLIENT_ID_FILE \
- --outfile=$$top_builddir/config.h
-configh.CONFIG += no_link
+SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
-QMAKE_EXTRA_COMPILERS += configh
-PRE_TARGETDEPS += compiler_configh_make_all
+include(translations/translations.pri)
-DEFINES += VERSION_STR=\\\"$$system($${top_srcdir}/scripts/get_version_str.sh)\\\"
+VERSION_RUN = $$system(bash $${top_srcdir}/scripts/get_version_str.sh)
+DEFINES += VERSION_STR=\\\"$$system(cat $${top_srcdir}/scripts/version-str)\\\"
licenses.files = $$files($$top_srcdir/LICENSE.*)
licenses.path = /usr/share/$${TARGET}/licenses
@@ -99,13 +90,3 @@ SOURCES += $$QML_SOURCES
RESOURCES += \
YTPlayer.qrc
-
-mcc_data.target = mcc-data
-mcc_data.commands = \
- $$top_srcdir/scripts/mcc-data-util.py \
- --keyfile=$$top_srcdir/youtube-data-api-v3.key \
- --mccfile=$$top_srcdir/resources/mcc-data.json \
- --verbose --mode check
-
-QMAKE_EXTRA_TARGETS += mcc-data
-PRE_TARGETDEPS += mcc-data
diff --git a/icons/108x108/harbour-ytplayer.png b/icons/108x108/harbour-ytplayer.png
new file mode 100644
index 0000000..fff0281
Binary files /dev/null and b/icons/108x108/harbour-ytplayer.png differ
diff --git a/icons/128x128/harbour-ytplayer.png b/icons/128x128/harbour-ytplayer.png
new file mode 100644
index 0000000..1867e66
Binary files /dev/null and b/icons/128x128/harbour-ytplayer.png differ
diff --git a/icons/172x172/harbour-ytplayer.png b/icons/172x172/harbour-ytplayer.png
new file mode 100644
index 0000000..89bdb3e
Binary files /dev/null and b/icons/172x172/harbour-ytplayer.png differ
diff --git a/icons/86x86/harbour-ytplayer.png b/icons/86x86/harbour-ytplayer.png
new file mode 100644
index 0000000..bc824bb
Binary files /dev/null and b/icons/86x86/harbour-ytplayer.png differ
diff --git a/languages/translations.json b/languages/translations.json
deleted file mode 100644
index 9777976..0000000
--- a/languages/translations.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "default" : "en_GB",
- "items" : [
- {
- "name" : "Čeština",
- "code" : "cs_CZ",
- "authors" : [
- "Bobsik"
- ]
- },
- {
- "name" : "Deutsch",
- "code" : "de",
- "authors" : [
- "Björn Bidar ",
- "Pascal Schmid"
- ]
- },
- {
- "name" : "English (UK)",
- "code" : "en_GB",
- "authors" : [
- "Piotr Tworek "
- ]
- },
- {
- "name" : "Italiano",
- "code" : "it_IT",
- "authors" : [
- "Gio Scino"
- ]
- },
- {
- "name" : "Nederlands",
- "code" : "nl_NL",
- "authors" : [
- "Heimen Stoffels"
- ]
- },
- {
- "name" : "Русский",
- "code" : "ru_RU",
- "authors" : [
- "Petr Tsymbarovich "
- ]
- },
- {
- "name" : "Svenska",
- "code" : "sv",
- "authors" : [
- "Åke Engelbrektson "
- ]
- }
- ]
-}
diff --git a/languages/translations.pri b/languages/translations.pri
deleted file mode 100644
index 3a5efa9..0000000
--- a/languages/translations.pri
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (c) 2015 Piotr Tworek. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE.YTPlayer file.
-
-TRANSLATIONS += \
- languages/cs_CZ.ts \
- languages/de.ts \
- languages/en_GB.ts \
- languages/it_IT.ts \
- languages/nl_NL.ts \
- languages/ru_RU.ts \
- languages/sv.ts
-
-OTHER_FILES += languages/translations.json
-
-updateqm.input = TRANSLATIONS
-updateqm.output = $$top_builddir/languages/${QMAKE_FILE_BASE}.qm
-updateqm.commands = \
- lrelease -idbased ${QMAKE_FILE_IN} \
- -qm $$top_builddir/languages/${QMAKE_FILE_BASE}.qm
-updateqm.CONFIG += no_link
-QMAKE_EXTRA_COMPILERS += updateqm
-
-PRE_TARGETDEPS += compiler_updateqm_make_all
-
-localization.files = $$files($$top_builddir/languages/*.qm)
-localization.path = /usr/share/$${TARGET}/languages
-
-INSTALLS += localization
diff --git a/qml/YTPlayer.qml b/qml/YTPlayer.qml
index e5e2b59..3d1aa1a 100644
--- a/qml/YTPlayer.qml
+++ b/qml/YTPlayer.qml
@@ -29,7 +29,7 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
-import org.nemomobile.notifications 1.0
+import Nemo.Notifications 1.0
import harbour.ytplayer 1.0
import "pages"
@@ -40,13 +40,15 @@ ApplicationWindow
readonly property double thumbnailAspectRatio: 9 / 16
readonly property string youtubeIconsFontName: "youtube-icons"
readonly property int kMaxCoverThumbnailCount: 12
- readonly property int kThumbnailWidth: 120
readonly property color kBlackTransparentBg: "#AA000000"
readonly property string kYoutubeVideoUrlBase: "https://www.youtube.com/watch?v="
readonly property int kListAutoLoadItemThreshold: 10
readonly property int kStandardAnimationDuration: 250
readonly property int kLongAnimationDuration: 500
readonly property int kPreferredButtonWidth: 300
+ property string iconColor: Theme.darkPrimaryColor !== "undefined"
+ && Theme.darkPrimaryColor === Theme.primaryColor
+ ? "-black" : "-white"
initialPage: Component { MainMenu { } }
cover: YTNetworkManager.online ?
@@ -93,9 +95,8 @@ ApplicationWindow
function openLinkInBrowser(url) {
Log.debug("Opening link in browser: " + url)
- pageStack.push(Qt.resolvedUrl("pages/BrowserLauncher.qml"), {
- "url" : url,
- })
+ pageStack.push(Qt.resolvedUrl("pages/BrowserLauncher.qml"),
+ { "url" : url })
}
Timer {
@@ -106,6 +107,10 @@ ApplicationWindow
if (!YTNetworkManager.online) {
YTNetworkManager.onOnlineChanged(false)
}
+ if(!YTUpdater.ytdlExists()) {
+ pageStack.push(Qt.resolvedUrl("pages/Settings.qml"),
+ { autoUpdate: true })
+ }
}
}
diff --git a/qml/common/MainMenuItem.qml b/qml/common/MainMenuItem.qml
index 1b50fd3..bec6cd2 100644
--- a/qml/common/MainMenuItem.qml
+++ b/qml/common/MainMenuItem.qml
@@ -31,34 +31,38 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
BackgroundItem {
- id: root
-
property alias text: label.text
property alias icon: image.source
property int sidePadding: Theme.paddingMedium
property bool active: false
+ height: Theme.itemSizeSmall
- Row {
- id: wrapper
- x: root.sidePadding
- width: parent.width - 2 * root.sidePadding
- height: label.height + 2 * Theme.paddingMedium
- spacing: Theme.paddingLarge
-
- AsyncImage {
- id: image
- anchors.verticalCenter: parent.verticalCenter
- height: 64
- width: 64
- fillMode: Image.PreserveAspectFit
+ AsyncImage {
+ id: image
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ leftMargin: Theme.paddingLarge
+ }
+ width: parent.height * 0.7
+ height: parent.height * 0.7
+ fillMode: Image.PreserveAspectFit
+ }
+ Label {
+ id: label
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: image.right
+ right: parent.right
+ leftMargin: Theme.paddingLarge
+ rightMargin: sidePadding
}
- Label {
- id: label
- anchors.verticalCenter: parent.verticalCenter
- color: root.highlighted ? Theme.highlightColor : Theme.primaryColor
- font.family: Theme.fontFamilyHeading
- font.pixelSize: Theme.fontSizeLarge
- width: parent.width - image.width - 2 * parent.spacing
+ color: parent.highlighted
+ ? Theme.highlightColor
+ : Theme.primaryColor
+ font {
+ family: Theme.fontFamilyHeading
+ pixelSize: Theme.fontSizeMedium
}
}
}
diff --git a/qml/common/SettingsButton.qml b/qml/common/SettingsButton.qml
index 71abf03..bbdf19a 100644
--- a/qml/common/SettingsButton.qml
+++ b/qml/common/SettingsButton.qml
@@ -35,6 +35,7 @@ BackgroundItem {
property alias text: label.text
property bool selected: false
+ property alias color: label.color
Label {
id: label
diff --git a/qml/common/YTLikeButtons.qml b/qml/common/YTLikeButtons.qml
index 8bbda91..b8df5f4 100644
--- a/qml/common/YTLikeButtons.qml
+++ b/qml/common/YTLikeButtons.qml
@@ -131,7 +131,7 @@ Row {
Image {
property color hcolor: parent.pressed ? Theme.highlightColor : Theme.primaryColor
id: likeIcon
- source: "qrc:///icons/like-m.png"
+ source: "qrc:///icons/like-m"+iconColor+".png"
anchors.verticalCenter: parent.verticalCenter
opacity: parent.selected ? 1 : priv.inactiveButtonOpacity
Behavior on opacity {
@@ -190,7 +190,7 @@ Row {
Image {
property color hcolor: parent.pressed ? Theme.highlightColor : Theme.primaryColor
id: dislikeIcon
- source: "qrc:///icons/dislike-m.png"
+ source: "qrc:///icons/dislike-m"+iconColor+".png"
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
opacity: parent.selected ? 1 : priv.inactiveButtonOpacity
diff --git a/qml/common/YTListItem.qml b/qml/common/YTListItem.qml
index 865f821..c11a6d4 100644
--- a/qml/common/YTListItem.qml
+++ b/qml/common/YTListItem.qml
@@ -42,8 +42,8 @@ ListItem {
AsyncImage {
id: thumbnail
- width: kThumbnailWidth
- height: width * thumbnailAspectRatio
+ height: Theme.itemSizeMedium * 0.85
+ width: height / thumbnailAspectRatio
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
@@ -55,18 +55,19 @@ ListItem {
Rectangle {
anchors.bottom: parent.bottom
anchors.right: parent.right
- visible: (ytItem.duration.length > 0) &&
- parent.status === Image.Ready
+ visible: (ytItem.duration.length > 0) && parent.status === Image.Ready
color: "black"
height: childrenRect.height
width: childrenRect.width + 2 * Theme.paddingSmall
+ opacity: 0.8
Label {
x: Theme.paddingSmall
text: ytItem.duration.length > 0 ?
(new DJS.Duration(ytItem.duration)).asClock() : ""
- color: Theme.primaryColor
- font.pixelSize: Theme.fontSizeExtraSmall * 0.8
+ color: Theme.lightPrimaryColor
+ font.pixelSize: Theme.fontSizeExtraSmall * 0.7
+ font.weight: Font.Bold
horizontalAlignment: Text.AlignHCenter
}
}
@@ -80,14 +81,24 @@ ListItem {
wrapMode: Text.Wrap
anchors {
left: thumbnail.right
- right: parent.right
+ right: imageChannel.visible ? imageChannel.right : parent.right
leftMargin: Theme.paddingSmall
rightMargin: Theme.paddingSmall
verticalCenter: parent.verticalCenter
}
- font {
- family: Theme.fontFamily
- pixelSize: Theme.fontSizeExtraSmall
+ font.pixelSize: Theme.fontSizeSmall
+ }
+
+ Image {
+ id: imageChannel
+ source: "image://theme/icon-m-media-artists"
+ visible: youtubeId.kind === "youtube#channel"
+ width: Theme.iconSizeMedium
+ height: Theme.iconSizeMedium
+ anchors {
+ right: parent.right
+ rightMargin: Theme.paddingSmall
+ verticalCenter: parent.verticalCenter
}
}
diff --git a/qml/common/YTVideoList.qml b/qml/common/YTVideoList.qml
index 7bf5b0e..cf9dee6 100644
--- a/qml/common/YTVideoList.qml
+++ b/qml/common/YTVideoList.qml
@@ -66,6 +66,7 @@ YTListView {
}
delegate: YTListItem {
+ contentHeight: Theme.itemSizeMedium
width: parent.width
title: snippet.title
thumbnails: snippet.thumbnails
diff --git a/qml/cover/ChannelBrowser.qml b/qml/cover/ChannelBrowser.qml
index ec64d3b..9835c77 100644
--- a/qml/cover/ChannelBrowser.qml
+++ b/qml/cover/ChannelBrowser.qml
@@ -92,7 +92,7 @@ CoverBackground {
font.family: Theme.fontFamilyHeading
font.pixelSize: Theme.fontSizeSmall
font.bold: true
- color: Theme.primaryColor
+ color: Theme.lightPrimaryColor
maximumLineCount: 2
wrapMode: Text.WordWrap
elide: Text.ElideRight
diff --git a/qml/cover/Default.qml b/qml/cover/Default.qml
index 1a2d1d1..22715e8 100644
--- a/qml/cover/Default.qml
+++ b/qml/cover/Default.qml
@@ -114,7 +114,7 @@ CoverBackground {
font.family: Theme.fontFamilyHeading
font.pixelSize: Theme.fontSizeSmall
font.bold: true
- color: Theme.primaryColor
+ color: Theme.lightPrimaryColor
maximumLineCount: 2
wrapMode: Text.Wrap
text: "YTPlayer"
diff --git a/qml/cover/NetworkOffline.qml b/qml/cover/NetworkOffline.qml
index 8bb060f..87ea0a3 100644
--- a/qml/cover/NetworkOffline.qml
+++ b/qml/cover/NetworkOffline.qml
@@ -57,7 +57,7 @@ CoverBackground {
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Theme.fontSizeSmall
font.family: Theme.fontFamilyHeading
- color: Theme.primaryColor
+ color: Theme.lightPrimaryColor
maximumLineCount: 2
wrapMode: Text.Wrap
//: Network offline screen label
diff --git a/qml/pages/About.qml b/qml/pages/About.qml
index aa39be0..94cb386 100644
--- a/qml/pages/About.qml
+++ b/qml/pages/About.qml
@@ -12,135 +12,150 @@ Page {
requestCoverPage("Default.qml")
}
- Column {
- id: headerPart
- anchors.top: parent.top
- width: parent.width
+ SilicaFlickable {
+ id: aboutFlickable
+ anchors.fill: parent
+ contentHeight: aboutColumn.height + Theme.paddingLarge
- PageHeader {
- //: Title of about page
- //% "About YTPlayer"
- title: qsTrId("ytplayer-title-about")
- }
- Item {
- width: parent.width
- height: Theme.paddingMedium
- }
- Image {
- anchors.horizontalCenter: parent.horizontalCenter
- height: 256
- fillMode: Image.PreserveAspectFit
- source: "qrc:///logo.png"
- }
- Item {
- width: parent.width
- height: Theme.paddingMedium
- }
- Label {
- width: parent.width
- anchors.horizontalCenter: parent.horizontalCenter
- font.pixelSize: Theme.fontSizeSmall
- wrapMode: Text.WordWrap
- maximumLineCount: 2
- horizontalAlignment: Text.AlignHCenter
- //: YTPlayer application description in about page
- //% "Unofficial YouTube client for Sailfish OS"
- text: qsTrId("ytplayer-label-application-description")
- }
- Item {
- width: parent.width
- height: Theme.paddingMedium
- }
- Label {
- anchors.horizontalCenter: parent.horizontalCenter
- font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.secondaryColor
- //: Region code field value
- //% "Region code: %1"
- text: qsTrId("ytplayer-label-region-code").arg(regionCode)
- }
- Label {
- anchors.horizontalCenter: parent.horizontalCenter
- font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.secondaryColor
- //: Version label value
- //% "Version: %1"
- text: qsTrId("ytplayer-label-version").arg(YTUtils.version)
- }
- Item {
- width: parent.width
- height: Theme.paddingMedium
- }
- Label {
- anchors.horizontalCenter: parent.horizontalCenter
- font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.secondaryColor
- text: "Copyright \u00A9 2014-2015 Piotr Tworek"
- }
- Label {
- width: parent.width
- anchors.horizontalCenter: parent.horizontalCenter
- font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.secondaryColor
- wrapMode: Text.WordWrap
- maximumLineCount: 2
- horizontalAlignment: Text.AlignHCenter
- //: Label displaying YTPlayer licensing information
- //% "YTPlayer is licensed under 3-clause BSD License"
- text: qsTrId("ytplayer-label-application-license")
- }
- }
+ VerticalScrollDecorator { flickable: aboutFlickable }
- Item {
- anchors.top: headerPart.bottom
- anchors.bottom: urlPart.top
- width: parent.width
Column {
+ id: aboutColumn
+ anchors.top: parent.top
width: parent.width
- anchors.centerIn: parent
- readonly property real buttonWidth: Math.max(kPreferredButtonWidth, b1.implicitWidth,
- b2.implicitWidth, b2.implicitWidth)
- Button {
- id: b1
- width: parent.buttonWidth
+ spacing: Theme.paddingLarge
+
+ PageHeader {
+ //: Title of about page
+ //% "About YTPlayer"
+ title: qsTrId("ytplayer-title-about")
+ }
+ Image {
anchors.horizontalCenter: parent.horizontalCenter
- //: Button for showing license viewer page
- //% "View license"
- text: qsTrId("ytplayer-action-view-license")
- onClicked: pageStack.push(Qt.resolvedUrl("LicenseViewer.qml"), {
- "licenseFile": "LICENSE.YTPlayer"
- })
+ height: Theme.itemSizeMedium
+ width: Theme.itemSizeMedium
+ fillMode: Image.PreserveAspectFit
+ source: "qrc:///logo.png"
}
- Item { height: Theme.paddingLarge; width: parent.width }
- Button {
- id: b2
- width: parent.buttonWidth
+ Label {
+ width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
- //: Label for button showing third party software listing page
- //% "Third party software"
- text: qsTrId("ytplayer-action-third-party-software")
- onClicked: pageStack.push(Qt.resolvedUrl("ThirdPartySoftware.qml"))
+ font.pixelSize: Theme.fontSizeSmall
+ wrapMode: Text.WordWrap
+ maximumLineCount: 2
+ horizontalAlignment: Text.AlignHCenter
+ //: YTPlayer application description in about page
+ //% "Unofficial YouTube client for Sailfish OS"
+ text: qsTrId("ytplayer-label-application-description")
}
- Item { height: Theme.paddingLarge; width: parent.width }
- Button {
- id: b3
- width: parent.buttonWidth
+ Label {
anchors.horizontalCenter: parent.horizontalCenter
- //: Label for button showing application translation credits page
- //% "Translations"
- text: qsTrId("ytplayer-action-translation-credits")
- onClicked: pageStack.push(Qt.resolvedUrl("TranslationCredits.qml"))
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.secondaryColor
+ //: Region code field value
+ //% "Region code: %1"
+ text: qsTrId("ytplayer-label-region-code").arg(regionCode)
+ }
+ Label {
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.secondaryColor
+ //: Version label value
+ //% "Version: %1"
+ text: qsTrId("ytplayer-label-version").arg(YTUtils.version)
+ }
+ Label {
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.secondaryColor
+ horizontalAlignment: Text.AlignHCenter
+ text: "Copyright \u00A9 2014-2015 Piotr Tworek\n"
+ +"2015-2018 Petr Tsymbarovich\n"
+ +"2019-2020 Matti Viljanen"
+ }
+ Label {
+ width: parent.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.secondaryColor
+ wrapMode: Text.WordWrap
+ maximumLineCount: 2
+ horizontalAlignment: Text.AlignHCenter
+ //: Label displaying YTPlayer licensing information
+ //% "YTPlayer is licensed under 3-clause BSD License"
+ text: qsTrId("ytplayer-label-application-license")
+ }
+ Column {
+ width: parent.width
+ spacing: Theme.paddingLarge
+ readonly property real buttonWidth: Math.max(kPreferredButtonWidth,
+ b1.implicitWidth,
+ b2.implicitWidth,
+ b3.implicitWidth,
+ b4.implicitWidth)
+ Button {
+ id: b1
+ width: parent.buttonWidth
+ anchors.horizontalCenter: parent.horizontalCenter
+ //: Button for showing license viewer page
+ //% "View license"
+ text: qsTrId("ytplayer-action-view-license")
+ onClicked: pageStack.push(Qt.resolvedUrl("LicenseViewer.qml"), { "licenseFile": "LICENSE.YTPlayer" })
+ }
+ Button {
+ id: b2
+ width: parent.buttonWidth
+ anchors.horizontalCenter: parent.horizontalCenter
+ //: Label for button showing third party software listing page
+ //% "Third party software"
+ text: qsTrId("ytplayer-action-third-party-software")
+ onClicked: pageStack.push(Qt.resolvedUrl("ThirdPartySoftware.qml"))
+ }
+ Button {
+ id: b3
+ width: parent.buttonWidth
+ anchors.horizontalCenter: parent.horizontalCenter
+ //: Label for button showing application translation credits page
+ //% "Translations"
+ text: qsTrId("ytplayer-action-translation-credits")
+ onClicked: pageStack.push(Qt.resolvedUrl("TranslationCredits.qml"))
+ }
+ Button {
+ id: b4
+ width: parent.buttonWidth
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "GitHub"
+ onClicked: Qt.openUrlExternally("https://github.com/direc85/sailfish-ytplayer")
+ }
+ }
+
+ Label {
+ width: parent.width - 2 * Theme.horizontalPageMargin
+ wrapMode: Text.WordWrap
+ font.pixelSize: Theme.fontSizeSmall
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: Theme.secondaryColor
+ //: Description for Ko-Fi donation link image
+ //% "The original creator, tworaz, deserves all the credit for this awesome app. If, however, you would like to give your support to the maintainer, you can buy him a nice cup of coffee!"
+ text: qsTrId("ytplayer-about-ko-fiz")
}
- }
- }
- Label {
- id: urlPart
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottom: parent.bottom
- anchors.bottomMargin: Theme.paddingSmall
- color: Theme.secondaryColor
- font.pixelSize: Theme.fontSizeTiny
- text: "https://github.com/tworaz/sailfish-ytplayer"
+ BackgroundItem {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: Theme.iconSizeExtraLarge * 1.2
+ height: Theme.iconSizeExtraLarge * 1.2
+ onClicked: Qt.openUrlExternally("https://ko-fi.com/direc85")
+ contentItem.radius: Theme.paddingSmall
+
+ Image {
+ anchors.centerIn: parent
+ source: "qrc:///ko-fi.png"
+ width: Theme.iconSizeExtraLarge
+ height: Theme.iconSizeExtraLarge
+ smooth: true
+ asynchronous: true
+ }
+ }
+ }
}
}
diff --git a/qml/pages/Account.qml b/qml/pages/Account.qml
index 7d96635..8b3f78f 100644
--- a/qml/pages/Account.qml
+++ b/qml/pages/Account.qml
@@ -44,7 +44,7 @@ Page {
//: YouTube subscribed channels page title
//% "Subscribed channels"
title: qsTrId("ytplayer-title-subscribed-channels")
- topPulleyVisible: true
+ topPulleyVisible: false
}
},
State {
@@ -206,6 +206,7 @@ Page {
}
delegate: YTListItem {
+ contentHeight: Theme.itemSizeMedium
title: snippet.title
thumbnails: snippet.thumbnails
youtubeId: {
diff --git a/qml/pages/ChannelBrowser.qml b/qml/pages/ChannelBrowser.qml
index 7cb2cf0..59a580b 100644
--- a/qml/pages/ChannelBrowser.qml
+++ b/qml/pages/ChannelBrowser.qml
@@ -30,7 +30,7 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.ytplayer 1.0
-import org.nemomobile.notifications 1.0
+import Nemo.Notifications 1.0
import "../common"
Page {
diff --git a/qml/pages/DownloadSettings.qml b/qml/pages/DownloadSettings.qml
index ff700e3..838fbd3 100644
--- a/qml/pages/DownloadSettings.qml
+++ b/qml/pages/DownloadSettings.qml
@@ -43,7 +43,7 @@ Page {
//% "Automatically resume downloads"
text: qsTrId("ytplayer-label-autoresume")
//: Description of video download auto resume switch in settings
- //% "On startup, resume all downloads which were either quened or "
+ //% "On startup, resume all downloads which were either queued or "
//% "in progress when YTPlayer was closed."
description: qsTrId("ytplayer-description-autoresume")
checked: YTPrefs.getBool("Download/ResumeOnStartup")
diff --git a/qml/pages/DownloadedVideos.qml b/qml/pages/DownloadedVideos.qml
index 291cb24..8ca8c16 100644
--- a/qml/pages/DownloadedVideos.qml
+++ b/qml/pages/DownloadedVideos.qml
@@ -73,7 +73,7 @@ Page {
AsyncImage {
id: thumbnail
- width: kThumbnailWidth
+ width: Theme.itemSizeMedium
height: width * thumbnailAspectRatio
anchors {
verticalCenter: parent.verticalCenter
diff --git a/qml/pages/Favorites.qml b/qml/pages/Favorites.qml
index c35c906..f2ebfe6 100644
--- a/qml/pages/Favorites.qml
+++ b/qml/pages/Favorites.qml
@@ -91,6 +91,7 @@ Page {
model: YTFavorites
delegate: YTListItem {
+ contentHeight: Theme.itemSizeMedium
title: video_title
duration: video_duration
menu: contextMenuComponent
diff --git a/qml/pages/LicenseViewer.qml b/qml/pages/LicenseViewer.qml
index 227584f..873b912 100644
--- a/qml/pages/LicenseViewer.qml
+++ b/qml/pages/LicenseViewer.qml
@@ -45,10 +45,11 @@ Page {
}
SilicaFlickable {
+ id: licenseFlickable
anchors.fill: parent
- anchors.leftMargin: Theme.paddingMedium
- anchors.rightMargin: Theme.paddingMedium
- contentHeight: column.height
+ contentHeight: column.height + Theme.paddingLarge
+
+ VerticalScrollDecorator { flickable: licenseFlickable }
Column {
id: column
@@ -61,14 +62,13 @@ Page {
}
Text {
id: licenseText
- width: parent.width
+ x: Theme.paddingMedium
+ width: parent.width - 2*x
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
text: YTUtils.getLicense(licenseFile)
wrapMode: Text.Wrap
}
}
-
- VerticalScrollDecorator {}
}
}
diff --git a/qml/pages/LogViewer.qml b/qml/pages/LogViewer.qml
index 2c57e38..57523cc 100644
--- a/qml/pages/LogViewer.qml
+++ b/qml/pages/LogViewer.qml
@@ -30,7 +30,7 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.ytplayer 1.0
-import org.nemomobile.notifications 1.0
+import Nemo.Notifications 1.0
Page {
allowedOrientations: Orientation.All
diff --git a/qml/pages/MainMenu.qml b/qml/pages/MainMenu.qml
index 3034bf6..cf916bc 100644
--- a/qml/pages/MainMenu.qml
+++ b/qml/pages/MainMenu.qml
@@ -94,7 +94,7 @@ Page {
//: Menu option to show about page
//% "About"
text: qsTrId("ytplayer-action-about")
- //icon: "qrc:///icons/info-64.png"
+ //icon: "qrc:///icons/info-64"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("About.qml"))
}
MenuItem {
@@ -142,7 +142,7 @@ Page {
//: Menu option responsible for showing user subscriptions page
//% "Subscriptions"
text: qsTrId("ytplayer-action-subscriptions")
- icon: "qrc:///icons/rss-m.png"
+ icon: "qrc:///icons/rss-m"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("Account.qml"),
{ "state" : "SUBSCRIPTION_CHANNELS" })
}
@@ -216,21 +216,21 @@ Page {
//: Menu option showing video favorites page
//% "Favorites"
text: qsTrId("ytplayer-acton-favorites")
- icon: "qrc:///icons/star-8-64.png"
+ icon: "qrc:///icons/star-8-64"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("Favorites.qml"))
}
MainMenuItem {
//: Menu option to show video categories page
//% "Categories"
text: qsTrId("ytplayer-action-video-categories")
- icon: "qrc:///icons/categorize-64.png"
+ icon: "qrc:///icons/categorize-64"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("VideoCategories.qml"))
}
MainMenuItem {
//: Menu option showing downloaded videos page
//% "Downloads"
text: qsTrId("ytplayer-action-downloaded-videos")
- icon: "qrc:///icons/downloaded-videos-64.png"
+ icon: "qrc:///icons/downloaded-videos-64"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("DownloadedVideos.qml"))
}
MainMenuItem {
@@ -238,7 +238,7 @@ Page {
//% "Recommendations"
text: qsTrId("ytplayer-action-recommended")
visible: priv.showAccount
- icon: "qrc:///icons/approval-64.png"
+ icon: "qrc:///icons/approval-64"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("Account.qml"),
{ "state" : "RECOMMENDED" })
}
@@ -246,7 +246,7 @@ Page {
//: Menu opion showing recently watched videos page
//% "Watched recently"
text: qsTrId("ytplayer-action-watched-recently")
- icon: "qrc:///icons/video-multi-m.png"
+ icon: "qrc:///icons/video-multi-m"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("WatchedRecently.qml"))
}
MainMenuItem {
@@ -254,7 +254,7 @@ Page {
//% "Likes"
text: qsTrId("ytplayer-action-likes")
visible: priv.showAccount
- icon: "qrc:///icons/like-m.png"
+ icon: "qrc:///icons/like-m"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("Account.qml"),
{ "state" : "LIKES" })
}
@@ -263,7 +263,7 @@ Page {
//% "Dislikes"
text: qsTrId("ytplayer-action-dislikes")
visible: priv.showAccount
- icon: "qrc:///icons/dislike-m.png"
+ icon: "qrc:///icons/dislike-m"+iconColor+".png"
onClicked: pageStack.push(Qt.resolvedUrl("Account.qml"),
{ "state" : "DISLIKES" })
}
diff --git a/qml/pages/PlayerSettings.qml b/qml/pages/PlayerSettings.qml
index 9b7d6b4..b94c36f 100644
--- a/qml/pages/PlayerSettings.qml
+++ b/qml/pages/PlayerSettings.qml
@@ -41,7 +41,7 @@ Page {
}
Slider {
- //: Lael for slider changing video player controls hide delay
+ //: Label for slider changing video player controls hide delay
//% "Controls hide delay"
label: qsTrId("ytplayer-label-controls-hide-delay")
width: parent.width
diff --git a/qml/pages/Search.qml b/qml/pages/Search.qml
index c2cb2ea..3539d3e 100644
--- a/qml/pages/Search.qml
+++ b/qml/pages/Search.qml
@@ -239,6 +239,7 @@ Page {
}
delegate: YTListItem {
+ contentHeight: Theme.itemSizeMedium
width: parent.width
title: snippet.title
thumbnails: snippet.thumbnails
diff --git a/qml/pages/Settings.qml b/qml/pages/Settings.qml
index 38b0706..d393c2a 100644
--- a/qml/pages/Settings.qml
+++ b/qml/pages/Settings.qml
@@ -15,9 +15,82 @@ Page {
if (status === PageStatus.Active) {
accountSwitch.checked = YTPrefs.isAuthEnabled()
requestCoverPage("Default.qml")
+ if(autoUpdate) {
+ // We have to use this so that the
+ // functions do not fire at page activation
+ updateButtonClicked = true
+ startUpdate()
+ }
}
}
+ // Update-related properties
+ property bool autoUpdate: false // Used from YTPlayer.qml
+ property string localVersion: YTUpdater.localVersion
+ property string remoteVersion: YTUpdater.remoteVersion
+ property bool updating: YTUpdater.updating
+ property bool updateButtonClicked: false
+
+ // Update check helper; just for convenience
+ function updateMenuItem(itemEnabled, spinnerEnabled, newText) {
+ updateYtdlButton.text = newText
+ updateYtdlButton.enabled = itemEnabled
+ updateYtdlIndicator.running = spinnerEnabled
+
+ }
+
+ // Phase 1: Check the local version
+ function startUpdate() {
+ //: Shown while checking for local version of youtube-dl
+ //% "Checking local version..."
+ updateMenuItem(false, true, qsTrId("ytplayer-update-checking-local-version"))
+ YTUpdater.checkLocalVersion()
+ }
+
+ // Phase 2: Check the remote version
+ onLocalVersionChanged: {
+ if(!updateButtonClicked || localVersion === "checkingLocalVersion")
+ return;
+ //: Shown while checking for remote version of youtube-dl
+ //% "Checking remote version..."
+ updateMenuItem(false, true, qsTrId("ytplayer-update-checking-remote-version"))
+ YTUpdater.checkRemoteVersion()
+ }
+
+ // Phase 3: Compare the versions, and update if needed, or stop here
+ onRemoteVersionChanged: {
+ if(!updateButtonClicked || remoteVersion === "checkingRemoteVersion")
+ return;
+ if(remoteVersion === "----.--.--")
+ //: Shown when checking youtube-dl version from the Internet failed
+ //% "Could not check for updates"
+ updateMenuItem(true, false, qsTrId("ytplayer-update-checking-remote-version-failed"))
+ else if(remoteVersion !== localVersion) {
+ //: Shown while downloading the youtube-dl update from the Internet
+ //% "Downloading youtube-dl..."
+ updateMenuItem(false, true, qsTrId("ytplayer-update-downloading"))
+ YTUpdater.startUpdate()
+ }
+ else
+ //: Shown when youtube-dl is up to date and no update is needed
+ //% "Youtube-dl is up to date"
+ updateMenuItem(false, false, qsTrId("ytplayer-update-up-to-date"))
+ }
+
+ // Phase 4: Verify the updated version, or inform about failure
+ onUpdatingChanged: {
+ if(!updateButtonClicked)
+ return;
+ if(localVersion !== remoteVersion)
+ //: Shown after youtube-dl update failed
+ //% "Updating youtube-dl failed"
+ updateMenuItem(false, false, qsTrId("ytplayer-update-failed"))
+ else(localVersion === remoteVersion)
+ //: Shown after youtube-dl update succeeded
+ //% "Updated youtube-dl succesfully"
+ updateMenuItem(false, false, qsTrId("ytplayer-update-successful"))
+ }
+
SilicaFlickable {
anchors.fill: parent
readonly property real _h: topColumn.height + bottomColumn.height
@@ -76,6 +149,37 @@ Page {
anchors.bottom: parent.bottom
anchors.bottomMargin: Theme.paddingLarge
+ Item {
+ height: updateYtdlButton.height
+ width: parent.width / parent.columns
+ SettingsButton {
+ id: updateYtdlButton
+ anchors.fill: parent
+ enabled: localVersion !== remoteVersion
+ text: {
+ if(localVersion !== remoteVersion)
+ //: MenuItem text for updating youtube-dl
+ //% "Update youtube-dl"
+ return qsTrId("ytplayer-update-youtubedl")
+ else
+ qsTrId("ytplayer-update-up-to-date")
+ }
+ color: (root.highlighted | root.selected) ? Theme.highlightColor : (enabled ? Theme.primaryColor : Theme.secondaryColor)
+ onClicked: {
+ // We have to use this so that the
+ // functions do not fire at page activation
+ updateButtonClicked = true
+ startUpdate()
+ }
+ }
+ BusyIndicator {
+ id: updateYtdlIndicator
+ anchors.centerIn: parent
+ size: BusyIndicatorSize.Medium
+ running: false
+ visible: running
+ }
+ }
SettingsButton {
width: parent.width / parent.columns
//: Label for menu option showing cache settings page
@@ -121,6 +225,15 @@ Page {
pageStack.push(Qt.resolvedUrl("SearchSettings.qml"))
}
}
+ SettingsButton {
+ width: parent.width / parent.columns
+ //: Label for menu option to enter YouTube API keys
+ //% "API keys"
+ text: qsTrId("ytplayer-action-set-api-keys")
+ onClicked: {
+ pageStack.push(Qt.resolvedUrl("APIKeys.qml"))
+ }
+ }
} // Column
VerticalScrollDecorator {}
diff --git a/qml/pages/TranslationCredits.qml b/qml/pages/TranslationCredits.qml
index 63e3f92..77844ef 100644
--- a/qml/pages/TranslationCredits.qml
+++ b/qml/pages/TranslationCredits.qml
@@ -34,7 +34,7 @@ Page {
allowedOrientations: Orientation.All
SilicaListView {
- id: listview
+ id: listView
anchors.fill: parent
PullDownMenu {
@@ -46,6 +46,8 @@ Page {
}
}
+ VerticalScrollDecorator { flickable: listView}
+
header: PageHeader {
//: Title of translation credits page
//% "Translations"
@@ -56,28 +58,29 @@ Page {
delegate: Column {
id: listItem
- width: parent.width
- property variant autors: listview.model[index].authors
+ x: Theme.paddingLarge
+ width: parent.width - 2*x
+ property variant authors: listView.model[index].authors
- Label {
- anchors.horizontalCenter: parent.horizontalCenter
- text: listview.model[index].name
- font.pixelSize: Theme.fontSizeLarge
+ SectionHeader {
+ text: listView.model[index].name
+ font.pixelSize: Theme.fontSizeSmall
}
Repeater {
- model: listItem.autors
+ model: listItem.authors
Label {
- anchors.horizontalCenter: parent.horizontalCenter
- text: listItem.autors[index]
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ bottomMargin: Theme.paddingSmall
+ }
+ text: listItem.authors[index]
font.pixelSize: Theme.fontSizeExtraSmall
+ width: parent.width
+ wrapMode: Text.Wrap
+ //horizontalAlignment: Text.AlignHCenter
}
}
- Item {
- width: parent.width
- height: Theme.paddingLarge
- }
}
- VerticalScrollDecorator {}
}
}
diff --git a/qml/pages/VideoCategories.qml b/qml/pages/VideoCategories.qml
index c8286e4..b237b24 100644
--- a/qml/pages/VideoCategories.qml
+++ b/qml/pages/VideoCategories.qml
@@ -83,31 +83,41 @@ Page {
delegate: BackgroundItem {
id: delegate
+ width: page.width
+ height: Theme.itemSizeSmall
- Row {
- x: Theme.paddingMedium
- width: page.width
- spacing: Theme.paddingLarge
- anchors.verticalCenter: parent.verticalCenter
-
- Text {
- anchors.verticalCenter: parent.verticalCenter
- horizontalAlignment: Text.AlignHCenter
- width: 60
- font.family: youtubeIconsFontName
- font.pixelSize: Theme.fontSizeLarge
- color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
- text: H.getYouTubeIconForCategoryId(id)
+ // The logo on the left is actually a font character!
+ // ...which actually causes the vertical align to be off.
+ Text {
+ id: catLogo
+ anchors {
+ left: parent.left
+ verticalCenter: parent.verticalCenter
+ leftMargin: Theme.paddingLarge
}
+ horizontalAlignment: Text.AlignHCenter
+ width: height
+ font.pixelSize: Theme.fontSizeLarge
+ font.family: youtubeIconsFontName
+ color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
+ text: H.getYouTubeIconForCategoryId(id)
+ }
- Label {
- text: snippet.title
- anchors.verticalCenter: parent.verticalCenter
- color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
- font {
- pixelSize: Theme.fontSizeLarge
- family: Theme.fontFamilyHeading
- }
+ Label {
+ text: snippet.title
+ maximumLineCount: 1
+ truncationMode: TruncationMode.Fade
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: catLogo.right
+ right: parent.right
+ leftMargin: Theme.paddingLarge
+ rightMargin: Theme.paddingMedium
+ }
+ color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
+ font {
+ pixelSize: Theme.fontSizeLarge
+ family: Theme.fontFamilyHeading
}
}
diff --git a/qml/pages/VideoOverview.qml b/qml/pages/VideoOverview.qml
index cbf666f..400f13b 100644
--- a/qml/pages/VideoOverview.qml
+++ b/qml/pages/VideoOverview.qml
@@ -5,7 +5,7 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.ytplayer 1.0
-import org.nemomobile.notifications 1.0
+import Nemo.Notifications 1.0
import "../common/Helpers.js" as Helpers
import "../common/duration.js" as DJS
import "../common"
@@ -500,7 +500,75 @@ Page {
wrapMode: Text.Wrap
font.pixelSize: Theme.fontSizeExtraSmall
linkColor: Theme.highlightColor
- onLinkActivated: openLinkInBrowser(link)
+ onLinkActivated: {
+ var match = link.match(/^(https?\:\/\/)?(www\.)?youtu.*\/.*$/)
+ if (!match) {
+ console.log("The activated link is not an Youtube link")
+ openLinkInBrowser(link)
+ return
+ }
+
+ match = link.match(/^.*youtu.*(embed\/|watch\?v=|\&v=|\.be\/)([A-Za-z0-9_\-]{11}).*$/)
+ if (match) {
+ console.log("The link to a Youtube video was activated")
+ pageStack.push(Qt.resolvedUrl("VideoOverview.qml"), {
+ "videoId" : match[2]
+ })
+ return
+ }
+
+ match = link.match(/^.*\/channel\/([A-Za-z0-9_\-]{1,}).*$/)
+ if (match) {
+ console.log(match)
+ console.log("The link to a Youtube channel was activated")
+ pageStack.push(Qt.resolvedUrl("ChannelBrowser.qml"), {
+ "channelId" : match[1]
+ })
+ return
+ }
+
+ match = link.match(/^.*\/playlist.*$/)
+ if (match) {
+ console.log("The link to a Youtube playlist was activated")
+ openLinkInBrowser(link)
+ return
+ }
+
+ match = link.match(/^.*\/([A-Za-z0-9_\-]{1,}).*$/)
+ if (match) {
+ channelIdRequest.link = link
+ channelIdRequest.params = {
+ part : "id",
+ forUsername : match[1]
+ }
+ channelIdRequest.run()
+ }
+ }
+
+ YTRequest {
+ property string link
+
+ id: channelIdRequest
+ method: YTRequest.List
+ resource: "channels"
+
+ onSuccess: {
+ console.log(response)
+ console.assert(response.kind === "youtube#channelListResponse")
+ if (response.items.length === 0) {
+ console.log("Could not find a channel with username ", params.forUsername)
+ openLinkInBrowser(link)
+ return
+ }
+
+ var item = response.items[0]
+ console.assert(item.kind === "youtube#channel")
+ console.log("The link to a Youtube user was activated")
+ pageStack.push(Qt.resolvedUrl("ChannelBrowser.qml"), {
+ "channelId" : item.id
+ })
+ }
+ }
}
}
diff --git a/qml/pages/VideoPlayer.qml b/qml/pages/VideoPlayer.qml
index 7ee5e2e..9760578 100644
--- a/qml/pages/VideoPlayer.qml
+++ b/qml/pages/VideoPlayer.qml
@@ -5,8 +5,9 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import QtMultimedia 5.0
+import Sailfish.Media 1.0
import harbour.ytplayer 1.0
-import org.nemomobile.notifications 1.0
+import Nemo.Notifications 1.0
import "../common/Helpers.js" as H
import "../common"
@@ -171,6 +172,7 @@ Page {
PageHeader {
id: header
z: videoOutput.z + 2
+ visible: opacity > 0.0
Behavior on opacity {
FadeAnimation {}
}
@@ -184,13 +186,19 @@ Page {
color: "black"
opacity: 0.5
z: header.z - 1
+ visible: opacity > 0.0
Behavior on opacity {
FadeAnimation {}
}
}
Rectangle {
- color: "black"
+ color: Qt.application.active ? "black" : "transparent"
+ Behavior on color {
+ ColorAnimation {
+ duration: Qt.application.active ? 300 : 0
+ }
+ }
width: page.width
height: page.height
Text {
@@ -237,12 +245,12 @@ Page {
YTIconButton {
id: playButton
anchors.centerIn: parent
- source: "qrc:///icons/play-64.png"
+ source: "qrc:///icons/play-64-white.png"
}
YTIconButton {
id: pauseButton
anchors.centerIn: parent
- source: "qrc:///icons/pause-64.png"
+ source: "qrc:///icons/pause-64-white.png"
}
}
}
@@ -388,8 +396,9 @@ Page {
Text {
id: statusLabel
font.pixelSize: Theme.fontSizeSmall
- color: Theme.highlightColor
+ color: Theme.lightPrimaryColor !== "undefined" ? Theme.lightPrimaryColor : Theme.primaryColor
}
+ visible: opacity > 0.0
Behavior on opacity {
FadeAnimation {}
}
@@ -404,12 +413,16 @@ Page {
radius: 4.0
color: "black"
opacity: 0.0
+ visible: opacity > 0.0
Behavior on opacity {
FadeAnimation {}
}
}
Slider {
id: progressSlider
+ color: Theme.lightPrimaryColor !== "undefined" ? Theme.lightPrimaryColor : Theme.primaryColor
+ backgroundColor: Theme.lightSecondaryColor !== "undefined" ? Theme.lightSecondaryColor : Theme.secondaryColor
+ highlightColor: Theme.highlightColor
anchors.bottom: bottomMenu.top
width: parent.width
z: videoOutput.z + 2
@@ -417,11 +430,13 @@ Page {
enabled: true
minimumValue: 0
valueText: H.parseDuration(value)
+ valueLabelColor: Theme.lightPrimaryColor !== "undefined" ? Theme.lightPrimaryColor : Theme.primaryColor
onPressed: controlsTimer.stop()
onReleased: {
mediaPlayer.seek(value)
controlsTimer.startIfNeeded()
}
+ visible: opacity > 0.0
Behavior on opacity {
FadeAnimation {}
}
@@ -435,12 +450,13 @@ Page {
color: "black"
opacity: 0.5
z: progressSlider.z - 1
+ visible: opacity > 0.0
Behavior on opacity {
FadeAnimation {}
}
}
Text {
- color: "white"
+ color: Theme.lightPrimaryColor
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: Theme.paddingSmall
@@ -449,6 +465,7 @@ Page {
text: H.parseDuration(mediaPlayer.duration)
opacity: mediaPlayer.duration > 0 ? progressSliderBg.opacity * 2 : 0.0
z: progressSliderBg.z + 1
+ visible: opacity > 0.0
Behavior on opacity {
FadeAnimation {}
}
@@ -457,7 +474,7 @@ Page {
PushUpMenu {
id: bottomMenu
bottomMargin: Theme.paddingSmall
- visible: priv.controlsVisible && multipleQualitiesAvailable
+ visible: opacity > 0.0 && priv.controlsVisible && multipleQualitiesAvailable
property bool multipleQualitiesAvailable: false
property Item selectedItem
diff --git a/qml/pages/WatchedRecently.qml b/qml/pages/WatchedRecently.qml
index 445168c..5c14ad4 100644
--- a/qml/pages/WatchedRecently.qml
+++ b/qml/pages/WatchedRecently.qml
@@ -97,6 +97,7 @@ Page {
model: YTWatchedRecently
delegate: YTListItem {
+ contentHeight: Theme.itemSizeMedium
title: video_title
duration: video_duration
youtubeId: {
diff --git a/qml/pages/YTOAuth2.qml b/qml/pages/YTOAuth2.qml
index 70cca7c..00bc09f 100644
--- a/qml/pages/YTOAuth2.qml
+++ b/qml/pages/YTOAuth2.qml
@@ -31,7 +31,7 @@ import QtQuick 2.0
import QtWebKit 3.0
import Sailfish.Silica 1.0
import harbour.ytplayer 1.0
-import org.nemomobile.notifications 1.0
+import Nemo.Notifications 1.0
Page {
id: page
@@ -91,17 +91,13 @@ Page {
}
}
- SilicaWebView {
+ WebView {
id: webview
anchors.fill: parent
visible: false
property string _authCode: ""
- header: PageHeader {
- title: page.pageTitle
- }
-
url: request.oAuth2Url
onLoadingChanged: {
@@ -130,7 +126,7 @@ Page {
} else if (title.indexOf('Denied error') !== -1) {
Log.debug("Youtube OAuth access denied!")
//: Message informing the user about YouTube OAuth autorization denial
- //% "YouTube OAuth access denined!"
+ //% "YouTube OAuth access denied!"
failureNotification.previewBody = qsTrId("ytplayer-oauth-access-denied")
failureNotification.publish()
pageStack.navigateBack(PageStackAction.Animated)
diff --git a/resources/icons/approval-64-black.png b/resources/icons/approval-64-black.png
new file mode 100644
index 0000000..4ed3595
Binary files /dev/null and b/resources/icons/approval-64-black.png differ
diff --git a/resources/icons/approval-64.png b/resources/icons/approval-64-white.png
similarity index 100%
rename from resources/icons/approval-64.png
rename to resources/icons/approval-64-white.png
diff --git a/resources/icons/bookmark-2-64-black.png b/resources/icons/bookmark-2-64-black.png
new file mode 100644
index 0000000..d95fe32
Binary files /dev/null and b/resources/icons/bookmark-2-64-black.png differ
diff --git a/resources/icons/bookmark-2-64.png b/resources/icons/bookmark-2-64-white.png
similarity index 100%
rename from resources/icons/bookmark-2-64.png
rename to resources/icons/bookmark-2-64-white.png
diff --git a/resources/icons/categorize-64-black.png b/resources/icons/categorize-64-black.png
new file mode 100644
index 0000000..4753380
Binary files /dev/null and b/resources/icons/categorize-64-black.png differ
diff --git a/resources/icons/categorize-64.png b/resources/icons/categorize-64-white.png
similarity index 100%
rename from resources/icons/categorize-64.png
rename to resources/icons/categorize-64-white.png
diff --git a/resources/icons/dislike-m-black.png b/resources/icons/dislike-m-black.png
new file mode 100644
index 0000000..3b0721c
Binary files /dev/null and b/resources/icons/dislike-m-black.png differ
diff --git a/resources/icons/dislike-m.png b/resources/icons/dislike-m-white.png
similarity index 100%
rename from resources/icons/dislike-m.png
rename to resources/icons/dislike-m-white.png
diff --git a/resources/icons/downloaded-videos-64-black.png b/resources/icons/downloaded-videos-64-black.png
new file mode 100644
index 0000000..c227c46
Binary files /dev/null and b/resources/icons/downloaded-videos-64-black.png differ
diff --git a/resources/icons/downloaded-videos-64.png b/resources/icons/downloaded-videos-64-white.png
similarity index 100%
rename from resources/icons/downloaded-videos-64.png
rename to resources/icons/downloaded-videos-64-white.png
diff --git a/resources/icons/like-m-black.png b/resources/icons/like-m-black.png
new file mode 100644
index 0000000..0626bf8
Binary files /dev/null and b/resources/icons/like-m-black.png differ
diff --git a/resources/icons/like-m.png b/resources/icons/like-m-white.png
similarity index 100%
rename from resources/icons/like-m.png
rename to resources/icons/like-m-white.png
diff --git a/resources/icons/pause-64-black.png b/resources/icons/pause-64-black.png
new file mode 100644
index 0000000..b2bbe1c
Binary files /dev/null and b/resources/icons/pause-64-black.png differ
diff --git a/resources/icons/pause-64.png b/resources/icons/pause-64-white.png
similarity index 100%
rename from resources/icons/pause-64.png
rename to resources/icons/pause-64-white.png
diff --git a/resources/icons/play-64-black.png b/resources/icons/play-64-black.png
new file mode 100644
index 0000000..dac9624
Binary files /dev/null and b/resources/icons/play-64-black.png differ
diff --git a/resources/icons/play-64.png b/resources/icons/play-64-white.png
similarity index 100%
rename from resources/icons/play-64.png
rename to resources/icons/play-64-white.png
diff --git a/resources/icons/rss-m-black.png b/resources/icons/rss-m-black.png
new file mode 100644
index 0000000..224256e
Binary files /dev/null and b/resources/icons/rss-m-black.png differ
diff --git a/resources/icons/rss-m.png b/resources/icons/rss-m-white.png
similarity index 100%
rename from resources/icons/rss-m.png
rename to resources/icons/rss-m-white.png
diff --git a/resources/icons/search-m-black.png b/resources/icons/search-m-black.png
new file mode 100644
index 0000000..6f72b57
Binary files /dev/null and b/resources/icons/search-m-black.png differ
diff --git a/resources/icons/search-m.png b/resources/icons/search-m-white.png
similarity index 100%
rename from resources/icons/search-m.png
rename to resources/icons/search-m-white.png
diff --git a/resources/icons/star-8-64-black.png b/resources/icons/star-8-64-black.png
new file mode 100644
index 0000000..e15612d
Binary files /dev/null and b/resources/icons/star-8-64-black.png differ
diff --git a/resources/icons/star-8-64.png b/resources/icons/star-8-64-white.png
similarity index 100%
rename from resources/icons/star-8-64.png
rename to resources/icons/star-8-64-white.png
diff --git a/resources/icons/video-multi-m-black.png b/resources/icons/video-multi-m-black.png
new file mode 100644
index 0000000..ac5e201
Binary files /dev/null and b/resources/icons/video-multi-m-black.png differ
diff --git a/resources/icons/video-multi-m.png b/resources/icons/video-multi-m-white.png
similarity index 100%
rename from resources/icons/video-multi-m.png
rename to resources/icons/video-multi-m-white.png
diff --git a/resources/logo.png b/resources/logo.png
deleted file mode 100644
index 3125dc1..0000000
Binary files a/resources/logo.png and /dev/null differ
diff --git a/rpm/harbour-ytplayer.changes b/rpm/harbour-ytplayer.changes
new file mode 100644
index 0000000..ec5f36f
--- /dev/null
+++ b/rpm/harbour-ytplayer.changes
@@ -0,0 +1,93 @@
+* Tue Jun 27 2021 Matti Viljanen 0.6.18-1
+- Added youtube-dl update functionality in Settings
+- Read youtube-client-id.json and youtube-data-api-v3.key from Downloads
+- Improve error reporting a bit
+
+* Sun Jan 31 2021 Matti Viljanen 0.6.17-1
+- Use youtube-dl instead of youtube-dl-lite for now
+- Update youtube-dl to 2021.01.24.1
+- Remove preinstalled API keys
+- Enable (require) user supplied API keys
+- Release experimental aarch64 version
+
+* Thu Jun 11 2020 Matti Viljanen 0.6.16-1
+- Update youtube-dl-lite to 2020.05.08
+
+* Mon Jun 1 2020 Matti Viljanen 0.6.15-1
+- Revert "Recommened" videos change
+
+* Sun May 31 2020 Matti Viljanen 0.6.14-1
+- Remove "Latest" menu item from subscriptions
+- "Fix" "Recommened" videos in main menu
+- Update About page
+
+* Sat Mar 21 2020 Matti Viljanen 0.6.13-1
+- Update youtube-dl-lite to 2020.03.08
+
+* Tue Feb 25 2020 Matti Viljanen 0.6.12-1
+- BETA RELEASE
+- Uses custom version of youtube-dl
+- Update functionality temporarily disabled
+
+* Sun Feb 23 2020 Matti Viljanen 0.6.11-1
+- Fix version number on about page
+- Fix video player page on SFOS 2.2
+
+* Tue Sep 24 2019 Matti Viljanen 0.6.10-1
+- Update Chinese translation
+- Use .yaml file to generate .spec
+- Use git head revision in About page
+
+* Sun Sep 15 2019 Matti Viljanen 0.6.9-1
+- Remove unused 1080p menu element
+
+* Sun Sep 15 2019 Matti Viljanen 0.6.8-1
+- Fix updating youtube-dl
+- Use internal log when updating youtube-dl
+- Better propagate youtube-dl update internally
+- Translations refreshed
+
+* Fri May 24 2019 Matti Viljanen 0.6.7-1
+- Update German translation
+- Fix category cover page background
+
+* Mon May 20 2019 Matti Viljanen 0.6.6-1
+- Improve dark theme support
+- Fix version number on About page
+- Restore logo in various pages
+- Adjust main menu list item size
+- Adjust video list item size
+- Update Swedish translation
+
+* Sat May 18 2019 Matti Viljanen 0.6.5-1
+- Added youtube-dl update functionality in Settings
+- Added auto-updating youtube-dl, if it is missing
+- Not bundling youtube-dl anymore
+- Fix for light theme cover
+- Compiled using Sailfish Application SDK 2.1 (3.0.3.9)
+- Changelog added
+
+* Sat Mar 30 2019 Matti Viljanen 0.6.2-1
+- Fix quota issue (thanks for help, tworaz!)
+- Re-uploaded correct armv7hl build
+
+* Sat Mar 30 2019 Matti Viljanen 0.6.1-3
+- 0.6.1-RC3
+- Compile using Sailfish Application SDK 2.1 EA (3.0.3)
+- Update youtube-dl
+
+* Tue Feb 12 2019 Matti Viljanen 0.6.0-2
+- 0.6.0-RC2
+- Compile fixes
+- Enable youtube-dl lazy extractors
+- Add channel icon to search results for channels
+- Main menu, Categories list, Video list layout fixes
+- About, Translations and License layout fixes
+- About page credits updated
+
+* Mon Feb 11 2019 Matti Viljanen 0.6.0-1
+- 0.6.0-RC1
+- Update youtube-dl to 2019.02.09
+- Fix translations
+- Performance fixes
+- Tons of compile- and project-related fixes
diff --git a/rpm/harbour-ytplayer.spec b/rpm/harbour-ytplayer.spec
index 57e8bec..4a6aa70 100644
--- a/rpm/harbour-ytplayer.spec
+++ b/rpm/harbour-ytplayer.spec
@@ -1,26 +1,33 @@
-%{!?qtc_qmake:%define qtc_qmake %qmake}
-%{!?qtc_qmake5:%define qtc_qmake5 %qmake5}
-%{!?qtc_make:%define qtc_make make}
-%{?qtc_builddir:%define _builddir %qtc_builddir}
+#
+# Do NOT Edit the Auto-generated Part!
+# Generated by: spectacle version 0.32
+#
Name: harbour-ytplayer
+
+# >> macros
+# << macros
+
Summary: Native YouTube client for SailfishOS
-Version: 0.5.99
+Version: 0.6.18
Release: 1
-Group: Qt/Qt
+Group: Applications/Multimedia
License: BSD-3-Clause
-URL: https://github.com/tworaz/sailfish-ytplayer
+URL: https://github.com/direc85/sailfish-ytplayer
Source0: %{name}-%{version}.tar.bz2
+Source100: harbour-ytplayer.yaml
Requires: sailfishsilica-qt5 >= 0.10.9
Requires: pyotherside-qml-plugin-python3-qt5
-BuildRequires: pkgconfig(Qt5Quick)
-BuildRequires: pkgconfig(Qt5Qml)
+Requires: nemo-qml-plugin-notifications-qt5
+BuildRequires: pkgconfig(sailfishapp) >= 1.0.2
BuildRequires: pkgconfig(Qt5Core)
+BuildRequires: pkgconfig(Qt5Qml)
+BuildRequires: pkgconfig(Qt5Quick)
BuildRequires: pkgconfig(Qt5DBus)
-BuildRequires: pkgconfig(sailfishapp) >= 0.0.10
+BuildRequires: pkgconfig(Qt5Concurrent)
+BuildRequires: pkgconfig(nemonotifications-qt5)
BuildRequires: desktop-file-utils
-BuildRequires: zip
-BuildRequires: python3-base
+BuildRequires: qt5-qttools-linguist
%description
YTPlayer is an unofficial YouTube client for SailfishOS
@@ -29,23 +36,40 @@ YTPlayer is an unofficial YouTube client for SailfishOS
%prep
%setup -q -n %{name}-%{version}
+# >> setup
+# << setup
+
%build
-%qtc_qmake5
-%qtc_make %{?_smp_mflags}
+# >> build pre
+# << build pre
+
+%qmake5
+
+make %{?_smp_mflags}
+
+# >> build post
+# << build post
%install
rm -rf %{buildroot}
+# >> install pre
+# << install pre
%qmake5_install
+# >> install post
+# << install post
+
desktop-file-install --delete-original \
- --dir %{buildroot}%{_datadir}/applications \
+ --dir %{buildroot}%{_datadir}/applications \
%{buildroot}%{_datadir}/applications/*.desktop
%files
-%defattr(0644,root,root,-)
-%attr(0755,root,root) %{_bindir}/%{name}
-%attr(0755,root,root) %{_datadir}/%{name}/bin/youtube-dl
+%defattr(-,root,root,-)
+%{_bindir}
+%{_datadir}/%{name}
%{_datadir}/%{name}/licenses
-%{_datadir}/%{name}/languages
+%{_datadir}/%{name}/translations
%{_datadir}/applications/%{name}.desktop
-%{_datadir}/icons/hicolor/86x86/apps/%{name}.png
+%{_datadir}/icons/hicolor/*/apps/%{name}.png
+# >> files
+# << files
diff --git a/rpm/harbour-ytplayer.yaml b/rpm/harbour-ytplayer.yaml
new file mode 100644
index 0000000..d174574
--- /dev/null
+++ b/rpm/harbour-ytplayer.yaml
@@ -0,0 +1,51 @@
+Name: harbour-ytplayer
+Summary: Native YouTube client for SailfishOS
+Version: 0.6.18
+Release: 1
+# The contents of the Group field should be one of the groups listed here:
+# https://github.com/mer-tools/spectacle/blob/master/data/GROUPS
+Group: Applications/Multimedia
+URL: https://github.com/direc85/sailfish-ytplayer
+License: BSD-3-Clause
+# This must be generated before uploading a package to a remote build service.
+# Usually this line does not need to be modified.
+Sources:
+- '%{name}-%{version}.tar.bz2'
+Description: |
+ YTPlayer is an unofficial YouTube client for SailfishOS
+Configure: none
+Builder: qmake5
+
+# This section specifies build dependencies that are resolved using pkgconfig.
+# This is the preferred way of specifying build dependencies for your package.
+PkgConfigBR:
+ - sailfishapp >= 1.0.2
+ - Qt5Core
+ - Qt5Qml
+ - Qt5Quick
+ - Qt5DBus
+ - Qt5Concurrent
+ - nemonotifications-qt5
+
+# Build dependencies without a pkgconfig setup can be listed here
+PkgBR:
+ - desktop-file-utils
+ - qt5-qttools-linguist
+
+# Runtime dependencies which are not automatically detected
+Requires:
+ - sailfishsilica-qt5 >= 0.10.9
+ - pyotherside-qml-plugin-python3-qt5
+ - nemo-qml-plugin-notifications-qt5
+
+# All installed files
+Files:
+ - '%{_bindir}'
+ - '%{_datadir}/%{name}'
+ - '%{_datadir}/%{name}/licenses'
+ - '%{_datadir}/%{name}/translations'
+ - '%{_datadir}/applications/%{name}.desktop'
+ - '%{_datadir}/icons/hicolor/*/apps/%{name}.png'
+
+# For more information about yaml and what's supported in Sailfish OS
+# build system, please see https://wiki.merproject.org/wiki/Spectacle
diff --git a/scripts/generate-config-h.py b/scripts/generate-config-h.py
deleted file mode 100755
index 5473f3f..0000000
--- a/scripts/generate-config-h.py
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env python
-
-import re
-import json
-import sys, getopt
-
-from pprint import pprint
-
-def show_help():
- print(sys.argv[0] + ' -k -c -o ')
-
-def warn(msg):
- sys.stderr.write("WARNING: " + msg + "\n")
-
-def get_api_key_define(keyfile):
- f = open(keyfile, 'r')
- line = f.readline()
- line = line.rstrip("\n")
- f.close()
- out = "/*\n * Value obtained from: " + keyfile + "\n */\n"
- out += "#define YOUTUBE_DATA_API_V3_KEY \"" + line + "\"\n"
- return out
-
-def get_client_id_defines(idfile):
- f = open(idfile, 'r')
- data = json.load(f)
- f.close()
-
- if "installed" not in data:
- warn("\"installed\" key not found in " + idfile);
- return None
-
- dict = data["installed"]
-
- outstr = "/*\n * Values obtained from: %s" % idfile + "\n */\n"
-
- if "auth_uri" not in dict:
- warn("\"auth_uri\" key not found in " + idfile)
- return None
- outstr += "#define YOUTUBE_AUTH_URI \"" + dict["auth_uri"] + "\"\n"
-
- if "client_id" not in dict:
- warn("\"client_id\" key not found in " + idfile)
- return None
- outstr += "#define YOUTUBE_AUTH_CLIENT_ID \"" + dict["client_id"] + "\"\n"
-
- if "client_secret" not in dict:
- warn("\"client_secret\" key not found in " + idfile)
- return None
- outstr += "#define YOUTUBE_AUTH_CLIENT_SECRET \"" + dict["client_secret"] + "\"\n"
-
- if "token_uri" not in dict:
- warn("\"token_uri\" key not found in " + idfile)
- return None
- outstr += "#define YOUTUBE_AUTH_TOKEN_URI \"" + dict["token_uri"] + "\"\n"
-
- if "redirect_uris" not in dict:
- warn("\n\"redirect_uris\" key not found in " + idfile)
- return None
-
- supported_redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
- support_urn_oob = False
- for uri in dict["redirect_uris"]:
- if uri == supported_redirect_uri:
- support_urn_oob = True
- break
-
- if not support_urn_oob:
- warn('"' + supported_redirect_uri + '" redirect type not supported by given client id!')
- return None
-
- outstr += '#define YOUTUBE_AUTH_REDIRECT_URI \"' + supported_redirect_uri + "\"\n"
-
- return outstr
-
-def main(argv):
- outputfile = None
- keyfile = None
- idfile = None
-
- try:
- opts, args = getopt.getopt(argv,"hk:d:o:",["keyfile=", "idfile=" ,"outfile="])
- except getopt.GetoptError:
- show_help()
- sys.exit(2)
- for opt, arg in opts:
- if opt == '-h':
- show_help()
- sys.exit()
- elif opt in ("-o", "--outfile"):
- outputfile = arg
- elif opt in ("-k", "--keyfile"):
- keyfile = arg
- elif opt in ("-d", "--idfile"):
- idfile = arg
- else:
- show_help()
- sys.exit(3)
-
- out = None
- if outputfile:
- out = open(outputfile, "w")
- print("Generating config file: " + outputfile + "\n");
- else:
- sys.stderr.write("Generating config file\n");
- out = sys.stdout
-
- out.write("/*\n * Autogenerated by: %s" % (sys.argv[0]) + "\n */\n\n")
- out.write("#ifndef _CONFIG_H_\n")
- out.write("#define _CONFIG_H_\n\n")
-
- if keyfile:
- out.write(get_api_key_define(keyfile))
- out.write("\n")
-
- if idfile:
- defs = get_client_id_defines(idfile)
- out.write(get_client_id_defines(idfile))
- out.write("\n")
-
- out.write("#endif\n");
-
- if out != sys.stdout:
- out.close()
-
-if __name__ == "__main__":
- main(sys.argv[1:])
diff --git a/scripts/get_version_str.sh b/scripts/get_version_str.sh
index e7616b7..e7df6ec 100755
--- a/scripts/get_version_str.sh
+++ b/scripts/get_version_str.sh
@@ -1,13 +1,12 @@
#!/bin/sh
+cd "$(dirname "$0")"/..
+_BASE=$(grep -oE 'Version:[[:space:]]*[0-9.]*' rpm/harbour-ytplayer.spec | awk '{ print $2 }')
+_REV=$(grep -oE 'Release:[[:space:]]*[0-9.]*' rpm/harbour-ytplayer.spec | awk '{ print $2 }')
+_FILE=scripts/version-str
-_SCRIPT=$(readlink -f $0)
-_DIR=$(dirname $_SCRIPT)/..
-
-_BASE=$(grep -oE 'Version:[[:space:]]*[0-9.]*' $_DIR/rpm/harbour-ytplayer.spec | awk '{ print $2 }')
-
-if [ -d $_DIR/.git ]; then
- _REV=$(git rev-parse --short HEAD)
- echo "$_BASE-$_REV"
-else
- echo $_BASE
+if [ -f .git/HEAD ] ; then
+ _REV=$(cat .git/$(cat .git/HEAD | awk '{ print $2 }') 2>&1 | cut -c1-7)
+ echo "$_BASE-$_REV" > $_FILE
+elif [ ! -f $_FILE ]; then
+ echo "$_BASE-$_REV" > $_FILE
fi
diff --git a/scripts/mcc-data-util.py b/scripts/mcc-data-util.py
deleted file mode 100755
index 73361bc..0000000
--- a/scripts/mcc-data-util.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env python2
-
-import httplib, urllib, json
-import sys, os, getopt, re
-
-verbose = False
-
-def show_help():
- print ("%s [options]\n" % sys.argv[0])
- print (" --mode [check|generate], -m Select mode (required)")
- print (" --keyfile [file], -k YouTube data API key file (required)")
- print (" --mccfile [file], -c Mobile Country code file path (required)")
- print (" --verbose, -v Enable verbose log messages")
- print (" --help, -h Show this help message")
-
-
-def country_exists(country, mccData):
- for e in mccData:
- if e["gl"] == country["gl"]:
- return True
- return False
-
-
-def error(msg):
- sys.stderr.write("[ERROR] " + msg + "\n")
-
-def warn(msg):
- sys.stderr.write("[WARNING] " + msg + "\n")
-
-
-def get_supported_localizations(keypath):
- keyfile = open(keypath, 'r')
- key = keyfile.readline();
- #print("YouTube Data API v3 key: " + key)
- keyfile.close()
-
- conn = httplib.HTTPSConnection("www.googleapis.com")
- params = urllib.urlencode({'part' : 'snippet', 'key' : key})
- conn.request("GET", '/youtube/v3/i18nRegions?' + params)
- response = conn.getresponse()
-
- if (response.status != 200):
- print("Warning: Connection to YouTube data API failed")
- conn.close()
- return None
-
- data = json.load(response)
- conn.close()
- return data
-
-
-def check(mccpath, i18n_data):
- f = open(mccpath, 'r')
- mcc_data = json.load(f);
- f.close();
-
- missing = i18n_data[:]
- for country in i18n_data:
- gl = country["snippet"]["gl"]
- for key in mcc_data:
- if mcc_data[key]["gl"] == gl:
- missing.remove(country)
- break;
-
- if len(missing) > 0:
- warn ("No MCC data for %d countries" % len(missing))
- else:
- print ("[INFO] All localization regions supported by YouTube have entries in " + mccpath)
-
- if verbose:
- for country in missing:
- snippet = country["snippet"]
- warn ("No MCC data for %s (%s)" % (snippet["name"], snippet["gl"]))
-
- return 0
-
-
-def generate(mccpath, i18n_data):
- out_data = {}
-
- if mccpath and os.path.isfile(mccpath):
- f = open(mccpath, "r")
- out_data = json.load(f)
- f.close()
- temp = i18n_data[:]
- for country in i18n_data:
- gl = country["snippet"]["gl"]
- for key in out_data:
- if out_data[key]["gl"] == gl:
- temp.remove(country)
- break;
- i18n_data = temp
-
- for country in i18n_data:
- s = country["snippet"]
- try:
- response = raw_input ("Mobile country code(s) for %s (%s): " % (s["name"], s["gl"]) )
- except EOFError:
- sys.stdout.write('\n')
- continue
- except KeyboardInterrupt:
- sys.stdout.write('\n')
- break
-
- codes = re.split(r'\ +', response)
- for c in codes:
- mcc = int(c)
- if out_data.has_key(mcc):
- error("MCC code %d already exists for %s" % (mcc, out_data[mcc]["name"]))
- return 1
- out_data[mcc] = s;
-
- print ("[INFO] Writing MCC data to: " + mccpath)
- outfile = open(mccpath, 'w+')
- json.dump(out_data, outfile)
- outfile.close()
-
- return 0
-
-
-def main(argv):
- global verbose
- keypath = None
- mccpath = None
- mode = None
-
- try:
- opts, args = getopt.getopt(argv,"hvm:k:c:",
- ["help", "verbose", "mode=", "keyfile=", "mccfile="])
- except getopt.GetoptError:
- show_help()
- sys.exit(2)
- for opt, arg in opts:
- if opt == '-h':
- show_help()
- sys.exit(0)
- elif opt in ("-v", "--verbose"):
- verbose = True
- elif opt in ("-k", "--keyfile"):
- keypath = arg
- elif opt in ("-c", "--mccfile"):
- mccpath = arg
- elif opt in ("-m", "--mode"):
- mode = arg
-
- if not mode:
- show_help()
- sys.exit(1)
-
- if not keypath:
- show_help()
- sys.exit(1)
-
- if not (mode == "check" or mode == "generate"):
- error ("Invalid mode: " + mode)
- sys.exit(3)
-
- if (not os.path.isfile(keypath)):
- error ("Keyfile does not exist: " + keypath)
- sys.exit(3)
-
- if not mccpath:
- error ("MCC Data file not specified (--mccfile)")
- sys.exit(3)
-
- if mode == "check" and not os.path.isfile(mccpath):
- error ("MCC Data file not exist: %s" % mccpath)
- sys.exit(3)
-
- i18n_data = get_supported_localizations(keypath)
- if not i18n_data:
- sys.exit(1)
-
- i18n_data = i18n_data["items"]
-
- if (mode == "check"):
- return check (mccpath, i18n_data)
- else:
- return generate (mccpath, i18n_data)
-
-
-if __name__ == "__main__":
- main(sys.argv[1:])
diff --git a/src/YTFavorites.cpp b/src/YTFavorites.cpp
index 82f83ab..b75ffd4 100644
--- a/src/YTFavorites.cpp
+++ b/src/YTFavorites.cpp
@@ -29,11 +29,6 @@
#include "YTFavorites.h"
-#include
-#include
-#include
-#include
-
namespace {
const char kCreateDbQueryText[] =
diff --git a/src/YTFavorites.h b/src/YTFavorites.h
index cc817df..f55bb32 100644
--- a/src/YTFavorites.h
+++ b/src/YTFavorites.h
@@ -33,6 +33,10 @@
#include "YTSqlListModel.h"
#include
+#include
+#include
+#include
+#include
class QSqlQuery;
diff --git a/src/YTListModel.cpp b/src/YTListModel.cpp
index badfffd..4e28c2a 100644
--- a/src/YTListModel.cpp
+++ b/src/YTListModel.cpp
@@ -29,9 +29,6 @@
#include "YTListModel.h"
-#include
-#include
-
YTListModel::YTListModel(QObject *parent)
: QAbstractListModel(parent)
, _filter(new YTListModelFilter(this))
diff --git a/src/YTListModel.h b/src/YTListModel.h
index f21b926..df133e0 100644
--- a/src/YTListModel.h
+++ b/src/YTListModel.h
@@ -34,7 +34,8 @@
#include
#include
#include
-
+#include
+#include
class YTListModelFilter: public QObject
{
diff --git a/src/YTLocalVideo.cpp b/src/YTLocalVideo.cpp
index 5c83e11..9e8f90c 100644
--- a/src/YTLocalVideo.cpp
+++ b/src/YTLocalVideo.cpp
@@ -29,8 +29,6 @@
#include "YTLocalVideo.h"
-#include
-
#include "YTLocalVideoManager.h"
#include "YTLocalVideoData.h"
#include "YTPlayer.h"
diff --git a/src/YTLocalVideo.h b/src/YTLocalVideo.h
index df8ca6a..6ebc3cf 100644
--- a/src/YTLocalVideo.h
+++ b/src/YTLocalVideo.h
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
class YTLocalVideoManager;
class YTLocalVideoData;
diff --git a/src/YTLocalVideoData.cpp b/src/YTLocalVideoData.cpp
index cc02028..651d099 100644
--- a/src/YTLocalVideoData.cpp
+++ b/src/YTLocalVideoData.cpp
@@ -29,14 +29,6 @@
#include "YTLocalVideoData.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
#include "YTLocalVideoManager.h"
#include "YTPlayer.h"
@@ -281,7 +273,7 @@ YTLocalVideoData::videoDownloadFinished()
Q_ASSERT(_videoFile->size() > 0);
Q_ASSERT(_videoPath.endsWith(kPartialContentSuffix));
- _videoPath = _videoPath.left(_videoPath.size() - strlen(kPartialContentSuffix));
+ _videoPath = _videoPath.left(_videoPath.size() - static_cast(strlen(kPartialContentSuffix)));
if (QFile(_videoPath).exists())
QFile(_videoPath).remove();
diff --git a/src/YTLocalVideoData.h b/src/YTLocalVideoData.h
index 4d1a3e3..eacbcaa 100644
--- a/src/YTLocalVideoData.h
+++ b/src/YTLocalVideoData.h
@@ -36,6 +36,13 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include "YTLocalVideo.h"
diff --git a/src/YTLocalVideoListModel.cpp b/src/YTLocalVideoListModel.cpp
index c14d170..ddab6f7 100644
--- a/src/YTLocalVideoListModel.cpp
+++ b/src/YTLocalVideoListModel.cpp
@@ -29,14 +29,6 @@
#include "YTLocalVideoListModel.h"
-#include
-#include
-#include
-#include
-#include
-
-#include
-
#include "YTLocalVideoManager.h"
#include "YTLocalVideo.h"
diff --git a/src/YTLocalVideoListModel.h b/src/YTLocalVideoListModel.h
index ded7304..f63c53e 100644
--- a/src/YTLocalVideoListModel.h
+++ b/src/YTLocalVideoListModel.h
@@ -34,6 +34,12 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
class YTLocalVideoManager;
diff --git a/src/YTLocalVideoManager.cpp b/src/YTLocalVideoManager.cpp
index 894f404..7028f8c 100644
--- a/src/YTLocalVideoManager.cpp
+++ b/src/YTLocalVideoManager.cpp
@@ -29,16 +29,6 @@
#include "YTLocalVideoManager.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
#include "YTNetworkManager.h"
#include "YTLocalVideoData.h"
#include "YTRequest.h"
@@ -49,13 +39,13 @@ class YTDownloadInfo : public QObject {
Q_OBJECT
public:
explicit YTDownloadInfo(QSharedPointer data,
- QNetworkAccessManager& nam, QObject *parent = 0)
+ QNetworkAccessManager& nam, QObject *parent = nullptr)
: QObject(parent)
, _downloadData(data)
- , _streamRequest(NULL)
- , _snippetRequest(NULL)
- , _thumbnailReply(NULL)
- , _videoReply(NULL)
+ , _streamRequest(nullptr)
+ , _snippetRequest(nullptr)
+ , _thumbnailReply(nullptr)
+ , _videoReply(nullptr)
, _initialVideoOffset(0)
, _networkAccessManager(nam)
{
@@ -130,7 +120,7 @@ private slots:
}
_thumbnailReply->disconnect();
_thumbnailReply->deleteLater();
- _thumbnailReply = NULL;
+ _thumbnailReply = nullptr;
}
void onVideoDownloadFinished()
@@ -148,7 +138,7 @@ private slots:
QNetworkRequest::RedirectionTargetAttribute).toUrl();
_videoReply->disconnect();
_videoReply->deleteLater();
- _videoReply = NULL;
+ _videoReply = nullptr;
startVideoDataDownload();
return;
} else {
@@ -162,16 +152,16 @@ private slots:
}
_videoReply->disconnect();
_videoReply->deleteLater();
- _videoReply = NULL;
+ _videoReply = nullptr;
}
void onVideoDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
Q_ASSERT(_videoReply);
if (bytesTotal != 0) {
- double p = (double)(_initialVideoOffset + bytesReceived) /
- (_initialVideoOffset + bytesTotal);
- _downloadData->reportVideoDownloadProgress(p * 100);
+ double p = (_initialVideoOffset + static_cast(bytesReceived)) /
+ (_initialVideoOffset + static_cast(bytesTotal));
+ _downloadData->reportVideoDownloadProgress(static_cast(p * 100.0));
}
_downloadData->videoDataFetched(_videoReply->readAll());
}
@@ -191,8 +181,6 @@ private slots:
quality = "720p";
} else if (map.contains("360p")) {
quality = "360p";
- } else if (map.contains("1080p")) {
- quality = "1080p";
} else {
Q_ASSERT(false);
onMetadataRequestError(response);
@@ -222,7 +210,7 @@ private slots:
_downloadData->setQuality(quality);
_streamRequest->deleteLater();
- _streamRequest = NULL;
+ _streamRequest = nullptr;
beginDataDownloadsIfPossible();
}
@@ -265,7 +253,7 @@ private slots:
_downloadData->setDuration(contentDetails["duration"].toString());
_snippetRequest->deleteLater();
- _snippetRequest = NULL;
+ _snippetRequest = nullptr;
beginDataDownloadsIfPossible();
}
@@ -284,7 +272,7 @@ private slots:
if (_snippetRequest->isRunning())
_snippetRequest->abort();
_snippetRequest->deleteLater();
- _snippetRequest = NULL;
+ _snippetRequest = nullptr;
qDebug() << "Cleaning up snippet request";
}
if (_streamRequest) {
@@ -292,7 +280,7 @@ private slots:
if (_streamRequest->isRunning())
_streamRequest->abort();
_streamRequest->deleteLater();
- _streamRequest = NULL;
+ _streamRequest = nullptr;
qDebug() << "Cleaning up stream request";
}
if (_videoReply) {
@@ -300,7 +288,7 @@ private slots:
if (_videoReply->isRunning())
_videoReply->abort();
_videoReply->deleteLater();
- _videoReply = NULL;
+ _videoReply = nullptr;
qDebug() << "Cleaning up video reply";
}
if (_thumbnailReply) {
@@ -308,7 +296,7 @@ private slots:
if (_thumbnailReply->isRunning())
_thumbnailReply->abort();
_thumbnailReply->deleteLater();
- _thumbnailReply = NULL;
+ _thumbnailReply = nullptr;
qDebug() << "Cleaning up thumbnail reply";
}
}
diff --git a/src/YTLocalVideoManager.h b/src/YTLocalVideoManager.h
index 0f20874..2574cd1 100644
--- a/src/YTLocalVideoManager.h
+++ b/src/YTLocalVideoManager.h
@@ -32,12 +32,21 @@
#include
#include
-#include
+#include
#include
#include
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
class QNetworkAccessManager;
class YTLocalVideoData;
diff --git a/src/YTLogger.cpp b/src/YTLogger.cpp
index 3fe552f..b0743de 100644
--- a/src/YTLogger.cpp
+++ b/src/YTLogger.cpp
@@ -29,10 +29,6 @@
#include "YTLogger.h"
-#include
-#include
-#include
-
namespace {
int kLogCacheSize = 200;
const char kLogFileName[] = "YTPlayer.log";
@@ -45,7 +41,7 @@ static QString _log_str_arr[] = {
QString("[INFO] ")
};
-QtMessageHandler YTLogger::_original_handler = NULL;
+QtMessageHandler YTLogger::_original_handler = nullptr;
QContiguousCache YTLogger::_log_cache =
QContiguousCache(kLogCacheSize);
diff --git a/src/YTLogger.h b/src/YTLogger.h
index f7700ec..cb4a871 100644
--- a/src/YTLogger.h
+++ b/src/YTLogger.h
@@ -37,6 +37,9 @@
#include
#include
#include
+#include
+#include
+#include
class YTLogger : public QAbstractListModel
{
diff --git a/src/YTNetworkManager.cpp b/src/YTNetworkManager.cpp
index c441dd2..ecc6e42 100644
--- a/src/YTNetworkManager.cpp
+++ b/src/YTNetworkManager.cpp
@@ -29,17 +29,6 @@
#include "YTNetworkManager.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
#include "YTPlayer.h"
#include "YTRequest.h"
@@ -50,11 +39,14 @@ _isCellular(const QNetworkConfiguration& config)
{
switch (config.bearerType()) {
case QNetworkConfiguration::Bearer2G:
- case QNetworkConfiguration::BearerBluetooth:
case QNetworkConfiguration::BearerHSPA:
case QNetworkConfiguration::BearerCDMA2000:
case QNetworkConfiguration::BearerWCDMA:
case QNetworkConfiguration::BearerWiMAX:
+ case QNetworkConfiguration::BearerEVDO:
+ case QNetworkConfiguration::BearerLTE:
+ case QNetworkConfiguration::Bearer3G:
+ case QNetworkConfiguration::Bearer4G:
return true;
default:
return false;
@@ -217,7 +209,7 @@ YTNetworkManager::closeNetworkSession()
_session->close();
delete _session;
- _session = NULL;
+ _session = nullptr;
}
qint64
diff --git a/src/YTNetworkManager.h b/src/YTNetworkManager.h
index 918bf57..5c86241 100644
--- a/src/YTNetworkManager.h
+++ b/src/YTNetworkManager.h
@@ -33,6 +33,16 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
class QNetworkConfigurationManager;
class QNetworkAccessManager;
diff --git a/src/YTPlayer.cpp b/src/YTPlayer.cpp
index 519c7a9..55df722 100644
--- a/src/YTPlayer.cpp
+++ b/src/YTPlayer.cpp
@@ -27,21 +27,13 @@
* SUCH DAMAGE.
*/
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#ifdef QT_QML_DEBUG
+#include
+#endif
-#include "YTVideoDownloadNotification.h"
#include "YTPlayer.h"
+
+#include "YTVideoDownloadNotification.h"
#include "YTListModel.h"
#include "YTNetworkManager.h"
#include "YTLocalVideoManager.h"
@@ -56,6 +48,7 @@
#include "YTLogger.h"
#include "YTUtils.h"
#include "YTPrefs.h"
+#include "YTUpdater.h"
namespace {
const QString kApplicationDBFileName = "YTPlayer.sqlite";
@@ -79,8 +72,8 @@ InitApplicationDatabase()
QThread*
GetBackgroundTaskThread()
{
- static QThread* thread = NULL;
- if (thread == NULL) {
+ static QThread* thread = nullptr;
+ if (thread == nullptr) {
thread = new QThread();
thread->start();
thread->setPriority(QThread::LowPriority);
@@ -91,8 +84,8 @@ GetBackgroundTaskThread()
QNetworkDiskCache*
GetImageDiskCache()
{
- static QNetworkDiskCache* cache = NULL;
- if (cache == NULL) {
+ static QNetworkDiskCache* cache = nullptr;
+ if (cache == nullptr) {
cache = new QNetworkDiskCache();
QString datadir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
datadir += "/ImageCache";
@@ -108,8 +101,8 @@ GetImageDiskCache()
QNetworkDiskCache*
GetAPIResponseDiskCache()
{
- static QNetworkDiskCache* cache = NULL;
- if (cache == NULL) {
+ static QNetworkDiskCache* cache = nullptr;
+ if (cache == nullptr) {
cache = new QNetworkDiskCache();
QString datadir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
datadir += "/APIRequestCache";
@@ -137,6 +130,20 @@ class YTPNetworkAccessManagerFactory: public QQmlNetworkAccessManagerFactory
int
main(int argc, char *argv[])
{
+ // Some more speed & memory improvements
+ // Borrowed these from LLC MediaPlayer :)
+ setenv("QT_NO_FAST_MOVE", "0", 0);
+ setenv("QT_NO_FT_CACHE","0",0);
+ setenv("QT_NO_FAST_SCROLL","0",0);
+ setenv("QT_NO_ANTIALIASING","1",1);
+ setenv("QT_NO_FREE","0",0);
+ setenv("QT_PREDICT_FUTURE", "1", 1);
+ setenv("QT_NO_BUG", "1", 1);
+ setenv("QT_NO_QT", "1", 1);
+ // Taken from sailfish-browser
+ setenv("USE_ASYNC", "1", 1);
+ QQuickWindow::setDefaultAlphaBuffer(true);
+
QScopedPointer app(SailfishApp::application(argc, argv));
QScopedPointer view(SailfishApp::createView());
YTTranslations translations;
@@ -153,6 +160,8 @@ main(int argc, char *argv[])
// Make sure the logger is initialized
YTLogger::instance();
+ YTUpdater updater;
+
if (!YTTranslations::initialize()) {
qCritical() << "Failed to initialize YTTranslations!";
return -1;
@@ -181,6 +190,7 @@ main(int argc, char *argv[])
view->rootContext()->setContextProperty("YTTranslations", &translations);
view->rootContext()->setContextProperty("YTWatchedRecently", &watched_recently);
view->rootContext()->setContextProperty("YTFavorites", &favorites);
+ view->rootContext()->setContextProperty("YTUpdater", &updater);
view->engine()->addImportPath("qrc:/ui/qml/");
view->setSource(QUrl("qrc:/ui/qml/YTPlayer.qml"));
diff --git a/src/YTPlayer.h b/src/YTPlayer.h
index 272bd8d..3166793 100644
--- a/src/YTPlayer.h
+++ b/src/YTPlayer.h
@@ -30,8 +30,21 @@
#ifndef YTPLAYER_H
#define YTPLAYER_H
+#include
+#include
+#include
#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
QThread* GetBackgroundTaskThread();
QNetworkDiskCache* GetImageDiskCache();
diff --git a/src/YTPrefs.cpp b/src/YTPrefs.cpp
index 446391d..09cc5ed 100644
--- a/src/YTPrefs.cpp
+++ b/src/YTPrefs.cpp
@@ -29,11 +29,6 @@
#include "YTPrefs.h"
-#include
-#include
-#include
-#include
-
#include "YTLocalVideoManager.h"
const char kWiFiOnly[] = "WiFi";
@@ -94,6 +89,77 @@ YTPrefs::initialize()
if (!settings.contains(kSearchSuggestionEngineKey))
settings.setValue(kSearchSuggestionEngineKey,
kHistorySuggestionEngine);
+
+
+ if (!settings.contains("YouTube/DataURL"))
+ settings.setValue("YouTube/DataURL", "https://www.googleapis.com/youtube/v3/");
+ if (!settings.contains("YouTube/VideoInfoURL"))
+ settings.setValue("YouTube/VideoInfoURL","http://www.youtube.com/get_video_info");
+
+ // Not the best place to read and handle the JSON code, but here it is.
+ QFile keyFile(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + QDir::separator() + "youtube-data-api-v3.key");
+ QFile dataApiFile(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + QDir::separator() + "youtube-client-id.json");
+ if(keyFile.exists() && dataApiFile.exists() &&
+ keyFile.open(QFile::ReadOnly) && dataApiFile.open(QFile::ReadOnly)) {
+ qDebug() << "Trying to proccess youtube-client-id.json...";
+ QJsonParseError jsonError;
+ QByteArray bytes = dataApiFile.readAll();
+ QJsonDocument dataJsonD = QJsonDocument::fromJson(bytes, &jsonError);
+ qDebug() << "JSON parse result:" << jsonError.errorString();
+
+ QJsonObject installed = dataJsonD.object().value(QString("installed")).toObject();
+ settings.setValue("YouTube/AuthURI", installed["auth_uri"].toString());
+ qDebug() << "AuthURI" << settings.value("YouTube/AuthURI");
+ settings.setValue("YouTube/TokenUri",installed["token_uri"].toString());
+ qDebug() << "TokenUri" << settings.value("YouTube/TokenUri");
+ settings.setValue("YouTube/RedirectURI", installed["redirect_uris"].toArray()[0].toString());
+ qDebug() << "RedirectURI" << settings.value("YouTube/RedirectURI");
+
+ settings.setValue("YouTube/ClientID", installed["client_id"].toString());
+ qDebug() << "ClientID" << settings.value("YouTube/ClientID");
+ settings.setValue("YouTube/ClientSecret", installed["client_secret"].toString());
+ qDebug() << "ClientSecret" << settings.value("YouTube/ClientSecret");
+
+ QString oldKey = settings.value("YouTube/DataAPIv3Key","").toString();
+
+ qDebug() << "Trying to proccess youtube-client-id.json...";
+ settings.setValue("YouTube/DataAPIv3Key", QString(keyFile.readAll()).toUtf8());
+ qDebug() << "DataAPIv3Key" << settings.value("YouTube/DataAPIv3Key");
+
+ if(settings.value("YouTube/DataAPIv3Key").toString().count() == 0
+ || settings.value("YouTube/ClientSecret").toString().count() == 0
+ || settings.value("YouTube/ClientID").toString().count() == 0) {
+ Notification notification;
+ notification.setAppName("YTPlayer");
+ notification.setAppIcon("harbour-ytplayer");
+ //: Error while parsing user-supplied json and key files
+ //% "Could not parse %1 or %2"
+ notification.setPreviewBody(qtTrId("ytplayer-msg-error-parsing-json")
+ .arg("youtube-client-id.json", "youtube-data-api-v3.key"));
+ notification.publish();
+ }
+ else if(oldKey != settings.value("YouTube/DataAPIv3Key").toString()) {
+ settings.remove("YouTube/AccessToken");
+ settings.remove("YouTube/RefreshToken");
+ settings.remove("YouTube/AccessTokenType");
+ settings.setValue("AccountIntegration", false);
+ }
+ }
+ else if(settings.value("YouTube/DataAPIv3Key").toString().count() == 0
+ || settings.value("YouTube/ClientSecret").toString().count() == 0
+ || settings.value("YouTube/ClientID").toString().count() == 0) {
+ Notification notification;
+ notification.setAppName("YTPlayer");
+ //: User hasn't provided the .json and .key files in Downloads directory
+ //% "Files %1 and %2 not found in Downloads folder"
+ notification.setPreviewBody(qtTrId("ytplayer-msg-error-json-files-not-found")
+ .arg("youtube-client-id.json", "youtube-data-api-v3.key"));
+ notification.publish();
+ }
+ if(keyFile.isOpen())
+ keyFile.close();
+ if(dataApiFile.isOpen())
+ dataApiFile.close();
}
void
diff --git a/src/YTPrefs.h b/src/YTPrefs.h
index 7aae690..b027e09 100644
--- a/src/YTPrefs.h
+++ b/src/YTPrefs.h
@@ -32,6 +32,17 @@
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
extern const char kWiFiOnly[];
extern const char kCellularOnly[];
diff --git a/src/YTRequest.cpp b/src/YTRequest.cpp
index c937fc6..cf9117f 100644
--- a/src/YTRequest.cpp
+++ b/src/YTRequest.cpp
@@ -29,27 +29,13 @@
#include "YTRequest.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
#include "YTVideoUrlFetcher.h"
#include "YTNetworkManager.h"
#include "YTTranslations.h"
#include "YTPlayer.h"
#include "YTUtils.h"
-#include "config.h"
namespace {
-static const QString kYouTubeDataV3Url("https://www.googleapis.com/youtube/v3/");
-static const QString kYouTubeGetVideoInfoUrl("http://www.youtube.com/get_video_info");
static const QString kMaxResults("50"); // Maximum allowed by YouTube
static const int kMaxRetryCount = 3;
}
@@ -57,14 +43,15 @@ static const int kMaxRetryCount = 3;
static void
appendParams(QUrlQuery& query, QVariantMap& params)
{
- for (QVariantMap::const_iterator i = params.begin(); i != params.end(); ++i)
+ for (QVariantMap::const_iterator i = params.constBegin(); i != params.constEnd(); ++i)
query.addQueryItem(i.key(), i.value().toString());
}
static void
appendCommonParams(QUrlQuery& query)
{
- query.addQueryItem("key", YOUTUBE_DATA_API_V3_KEY);
+ QSettings settings;
+ query.addQueryItem("key", settings.value("YouTube/DataAPIv3Key").toString());
query.addQueryItem("regionCode", YTUtils::getRegionCode());
query.addQueryItem("maxResults", kMaxResults);
query.addQueryItem("hl", YTTranslations::language());
@@ -92,22 +79,22 @@ appendAuthHeader(QNetworkRequest& request)
static QString
methodToString(YTRequest::Method method)
{
- switch (method) {
- case YTRequest::List: return "list";
- case YTRequest::Post: return "post";
- case YTRequest::Delete: return "delete";
- default: return "unknown";
- }
+ if(method == YTRequest::List) return "list";
+ if(method == YTRequest::List) return "list";
+ if(method == YTRequest::Post) return "post";
+ if(method == YTRequest::Delete) return "delete";
+ return "unknown";
}
static QUrl
youtubeDataAPIUrl(QString resource, QVariantMap params)
{
QUrlQuery query;
+ QSettings settings;
appendParams(query, params);
appendCommonParams(query);
- QUrl url(kYouTubeDataV3Url + resource);
+ QUrl url(settings.value("YouTube/DataURL").toString() + resource);
url.setQuery(query);
return url;
}
@@ -116,6 +103,7 @@ static QUrl
youtubeVideoInfoUrl(QVariantMap params)
{
QUrlQuery query;
+ QSettings settings;
appendParams(query, params);
query.addQueryItem("el", "player_embedded");
query.addQueryItem("gl", YTUtils::getRegionCode());
@@ -125,20 +113,20 @@ youtubeVideoInfoUrl(QVariantMap params)
query.addQueryItem("hl", "en");
}
- QUrl url(kYouTubeGetVideoInfoUrl);
+ QUrl url(settings.value("YouTube/VideoInfoURL").toString());
url.setQuery(query);
return url;
}
YTRequest::YTRequest(QObject *parent, QNetworkAccessManager* nam)
: QObject(parent)
- , _reply(NULL)
- , _token_reply(NULL)
- , _url_fetcher(NULL)
+ , _reply(nullptr)
+ , _token_reply(nullptr)
+ , _url_fetcher(nullptr)
, _network_access_manager(nam ? *nam : GetNetworkAccessManager())
, _loaded(false)
, _busy(false)
- , _model(NULL)
+ , _model(nullptr)
, _retryCount(0)
{
Q_ASSERT(thread() == _network_access_manager.thread());
@@ -150,18 +138,17 @@ YTRequest::~YTRequest()
if (!_reply->isFinished())
_reply->abort();
_reply->deleteLater();
- _reply = NULL;
+ _reply = nullptr;
}
if (_token_reply) {
if (!_token_reply->isFinished())
_token_reply->abort();
- _reply->deleteLater();
- _token_reply = NULL;
+ _token_reply = nullptr;
}
if (_url_fetcher) {
_url_fetcher->disconnect();
_url_fetcher->deleteLater();
- _url_fetcher = NULL;
+ _url_fetcher = nullptr;
}
}
@@ -248,13 +235,13 @@ YTRequest::onTokenRequestFinished()
handleError(_token_reply);
if (_reply) {
delete _reply;
- _reply = NULL;
+ _reply = nullptr;
}
break;
}
_token_reply->deleteLater();
- _token_reply = NULL;
+ _token_reply = nullptr;
}
void
@@ -262,11 +249,13 @@ YTRequest::onFinished()
{
Q_ASSERT(_reply);
+ QSettings settings;
+
bool busy = false;
switch (_reply->error()) {
case QNetworkReply::NoError:
- if (_reply->request().url().toString().startsWith(kYouTubeGetVideoInfoUrl)) {
+ if (_reply->request().url().toString().startsWith(settings.value("YouTube/VideoInfoURL").toString())) {
if (!handleVideoInfoReply(_reply)) {
busy = true;
break;
@@ -303,13 +292,14 @@ YTRequest::onFinished()
refreshToken();
break;
}
+ /* fall thru */
default:
handleError(_reply);
break;
}
_reply->deleteLater();
- _reply = NULL;
+ _reply = nullptr;
setBusy(busy);
}
@@ -358,6 +348,18 @@ YTRequest::handleError(QNetworkReply *reply)
QByteArray data = reply->readAll();
QJsonDocument json = QJsonDocument::fromJson(data);
qCritical() << "API Error: " << json;
+
+ QString message = json.object().value(QString("error")).toObject()["message"].toString();
+ if(message.length() > 0) {
+ message.remove(QRegExp("<[^>]*>"));
+
+ Notification notification;
+ notification.setAppName("YTPlayer");
+ notification.setAppIcon("harbour-ytplayer");
+ notification.setPreviewBody(message);
+ notification.publish();
+ }
+
emit error(QVariant(json.object()));
} else {
QVariantMap map;
@@ -471,9 +473,6 @@ YTRequest::handleVideoInfoReply(QNetworkReply *reply)
case 22: // MP4 1280 x 720
outMap.insert("720p", streamDetailsMap);
break;
- case 37: // MP4 1920 x 1080
- outMap.insert("1080p", streamDetailsMap);
- break;
}
}
@@ -484,26 +483,29 @@ YTRequest::handleVideoInfoReply(QNetworkReply *reply)
void
YTRequest::requestToken()
{
+ QSettings settings;
QUrlQuery query;
+ QSettings settings;
appendParams(query, _params);
//query.addQueryItem("code", authCode);
- query.addQueryItem("client_id", YOUTUBE_AUTH_CLIENT_ID);
- query.addQueryItem("client_secret", YOUTUBE_AUTH_CLIENT_SECRET);
+ query.addQueryItem("client_id", settings.value("YouTube/ClientID").toString());
+ query.addQueryItem("client_secret", settings.value("YouTube/ClientSecret").toString());
+
query.addQueryItem("redirect_uri", "urn:ietf:wg:oauth:2.0:oob");
query.addQueryItem("grant_type", "authorization_code");
QByteArray data = query.toString(QUrl::FullyEncoded).toLocal8Bit();
qDebug() << "Requesting YouTube OAuth2 tokens";
- QNetworkRequest request(QUrl(YOUTUBE_AUTH_TOKEN_URI));
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
+ QNetworkRequest* request = new QNetworkRequest(QUrl(settings.value("YouTube/TokenUri").toString()));
+ request->setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
if (_token_reply) {
Q_ASSERT(_token_reply->isFinished());
delete _token_reply;
}
- _token_reply = _network_access_manager.post(request, data);
+ _token_reply = _network_access_manager.post(*request, data);
connect(_token_reply, SIGNAL(finished()), this, SLOT(onTokenRequestFinished()));
}
@@ -516,21 +518,21 @@ YTRequest::refreshToken()
qDebug() << "OAuth2 token expired, refreshing";
Q_ASSERT(settings.value("YouTube/RefreshToken").isValid());
- query.addQueryItem("client_id", YOUTUBE_AUTH_CLIENT_ID);
- query.addQueryItem("client_secret", YOUTUBE_AUTH_CLIENT_SECRET);
+ query.addQueryItem("client_id", settings.value("YouTube/ClientID").toString());
+ query.addQueryItem("client_secret", settings.value("YouTube/ClientSecret").toString());
query.addQueryItem("refresh_token", settings.value("YouTube/RefreshToken").toString());
query.addQueryItem("grant_type", "refresh_token");
QByteArray data = query.toString(QUrl::FullyEncoded).toLocal8Bit();
- QNetworkRequest request(QUrl(YOUTUBE_AUTH_TOKEN_URI));
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
+ QNetworkRequest* request = new QNetworkRequest(QUrl(settings.value("YouTube/TokenUri").toString()));
+ request->setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
if (_token_reply) {
Q_ASSERT(_token_reply->isFinished());
delete _token_reply;
}
- _token_reply = _network_access_manager.post(request, data);
+ _token_reply = _network_access_manager.post(*request, data);
connect(_token_reply, SIGNAL(finished()), this, SLOT(onTokenRequestFinished()));
}
@@ -556,16 +558,18 @@ YTRequest::tryExternalStreamFetcher()
}
QUrl
-YTRequest::oAuth2Url() const
+YTRequest::oAuth2Url()
{
+ QSettings settings;
QUrlQuery query;
- query.addQueryItem("client_id", YOUTUBE_AUTH_CLIENT_ID);
- query.addQueryItem("redirect_uri", YOUTUBE_AUTH_REDIRECT_URI);
+ QSettings settings;
+ query.addQueryItem("client_id", settings.value("YouTube/ClientID").toString());
+ query.addQueryItem("redirect_uri", settings.value("YouTube/RedirectURI").toString());
query.addQueryItem("scope", "https://www.googleapis.com/auth/youtube");
query.addQueryItem("response_type", "code");
query.addQueryItem("access_type=", "offline");
- QUrl url(YOUTUBE_AUTH_URI);
+ QUrl url((settings.value("YouTube/AuthURI").toString()));
url.setQuery(query);
return url;
}
diff --git a/src/YTRequest.h b/src/YTRequest.h
index c2935a3..73fcbd3 100644
--- a/src/YTRequest.h
+++ b/src/YTRequest.h
@@ -34,10 +34,23 @@
#include
#include
#include
-#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
#include "YTListModel.h"
+#include "YTUpdater.h"
class QNetworkAccessManager;
class YTVideoUrlFetcher;
@@ -108,7 +121,7 @@ protected slots:
bool loaded() const { return _loaded; }
void setModel(YTListModel *model) { _model = model; }
YTListModel *model() const { return _model; }
- QUrl oAuth2Url() const;
+ QUrl oAuth2Url();
void setLoaded(bool);
void setBusy(bool);
diff --git a/src/YTSqlListModel.cpp b/src/YTSqlListModel.cpp
index 1c2e964..6d483d8 100644
--- a/src/YTSqlListModel.cpp
+++ b/src/YTSqlListModel.cpp
@@ -29,11 +29,6 @@
#include "YTSqlListModel.h"
-#include
-#include
-#include
-#include
-
namespace {
static int kResultPageSize = 50;
diff --git a/src/YTSqlListModel.h b/src/YTSqlListModel.h
index 4fd9d14..5d33034 100644
--- a/src/YTSqlListModel.h
+++ b/src/YTSqlListModel.h
@@ -33,6 +33,10 @@
#include
#include
#include
+#include
+#include
+#include
+#include
class QSqlQuery;
diff --git a/src/YTSuggestionEngine.cpp b/src/YTSuggestionEngine.cpp
index 49457ad..deaa2d5 100644
--- a/src/YTSuggestionEngine.cpp
+++ b/src/YTSuggestionEngine.cpp
@@ -29,15 +29,6 @@
#include "YTSuggestionEngine.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
#include "YTRequest.h"
#include "YTPrefs.h"
@@ -91,7 +82,7 @@ initDatabase()
YTSuggestionEngine::YTSuggestionEngine(QObject *parent)
: QObject(parent)
, _network_access_manager(YTRequest::GetNetworkAccessManager())
- , _reply(NULL)
+ , _reply(nullptr)
{
static bool db_initialized = false;
if (!db_initialized) {
@@ -113,7 +104,7 @@ YTSuggestionEngine::~YTSuggestionEngine()
{
if (_reply) {
delete _reply;
- _reply = NULL;
+ _reply = nullptr;
}
}
@@ -204,7 +195,7 @@ YTSuggestionEngine::onFinished()
}
_reply->deleteLater();
- _reply = NULL;
+ _reply = nullptr;
}
int
diff --git a/src/YTSuggestionEngine.h b/src/YTSuggestionEngine.h
index 2a36355..9d81dd0 100644
--- a/src/YTSuggestionEngine.h
+++ b/src/YTSuggestionEngine.h
@@ -30,11 +30,19 @@
#ifndef YTSUGGESTIONENGINE_H
#define YTSUGGESTIONENGINE_H
-#include
+#include
#include
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
class QNetworkReply;
diff --git a/src/YTTranslations.cpp b/src/YTTranslations.cpp
index 1a58349..655dc0a 100644
--- a/src/YTTranslations.cpp
+++ b/src/YTTranslations.cpp
@@ -29,14 +29,6 @@
#include "YTTranslations.h"
-#include