Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
PIM
KDE PIM Add-ons
Commits
12074996
Commit
12074996
authored
Oct 14, 2021
by
Friedrich W. H. Kossebau
Browse files
Update KOrganizer POTD plugin for current Wikipedia API
BUG: 369486
parent
5c4b134e
Pipeline
#89892
passed with stage
in 51 minutes and 1 second
Changes
5
Pipelines
3
Hide whitespace changes
Inline
Side-by-side
korganizer/plugins/picoftheday/CMakeLists.txt
View file @
12074996
...
...
@@ -4,6 +4,7 @@ add_library(korg_picoftheday MODULE)
target_sources
(
korg_picoftheday PRIVATE
configdialog.cpp
picoftheday.cpp
element.cpp
)
ecm_qt_declare_logging_category
(
korg_picoftheday HEADER korganizer_picoftheday_plugin_debug.h IDENTIFIER KORGANIZERPICOFTHEDAYPLUGIN_LOG CATEGORY_NAME org.kde.pim.korganizer_picoftheday_plugins
DESCRIPTION
"kdepim-addons (korganizer picoftheday plugins)"
...
...
korganizer/plugins/picoftheday/element.cpp
0 → 100644
View file @
12074996
/*
This file is part of KOrganizer.
SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
SPDX-FileCopyrightText: 2007 Loïc Corbasson <loic.corbasson@gmail.com>
SPDX-FileCopyrightText: 2021 Friedrich W. H. Kossebau <kossebau@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include
"element.h"
#include
"picoftheday.h"
#include
"korganizer_picoftheday_plugin_debug.h"
#include
<KIO/Scheduler>
#include
<KIO/StoredTransferJob>
#include
<KLocalizedString>
#include
<QJsonArray>
#include
<QJsonDocument>
#include
<QUrlQuery>
#include
<chrono>
using
namespace
std
::
chrono_literals
;
constexpr
auto
updateDelay
=
1s
;
void
ElementData
::
updateFetchedThumbSize
()
{
int
thumbWidth
=
mThumbSize
.
width
();
int
thumbHeight
=
static_cast
<
int
>
(
thumbWidth
*
mPictureHWRatio
);
if
(
mThumbSize
.
height
()
<
thumbHeight
)
{
/* if the requested height is less than the requested width * ratio
we would download too much, as the downloaded picture would be
taller than requested, so we adjust the width of the picture to
be downloaded in consequence */
thumbWidth
/=
(
thumbHeight
/
static_cast
<
float
>
(
mThumbSize
.
height
()));
thumbHeight
=
static_cast
<
int
>
(
thumbWidth
*
mPictureHWRatio
);
}
mFetchedThumbSize
=
QSize
(
thumbWidth
,
thumbHeight
);
}
POTDElement
::
POTDElement
(
const
QString
&
id
,
QDate
date
,
ElementData
*
data
)
:
Element
(
id
)
,
mDate
(
date
)
,
mData
(
data
)
,
mThumbImageGetDelayTimer
(
new
QTimer
(
this
))
{
mThumbImageGetDelayTimer
->
setSingleShot
(
true
);
mThumbImageGetDelayTimer
->
setInterval
(
updateDelay
);
connect
(
mThumbImageGetDelayTimer
,
&
QTimer
::
timeout
,
this
,
&
POTDElement
::
queryThumbImageInfoJson
);
// wait a bit to avoid data queries in case of quick paging through views
QTimer
::
singleShot
(
updateDelay
,
this
,
&
POTDElement
::
completeMissingData
);
}
POTDElement
::~
POTDElement
()
{
// reset thumb update state
if
(
mData
->
mState
>
DataLoaded
)
{
mData
->
mState
=
DataLoaded
;
}
Picoftheday
::
cacheData
(
mDate
,
mData
);
}
void
POTDElement
::
completeMissingData
()
{
if
(
mData
->
mState
<=
NeedingPageData
)
{
queryImagesJson
();
}
else
if
(
mData
->
mState
<=
NeedingBasicImageInfo
)
{
queryBasicImageInfoJson
();
}
else
if
(
mData
->
mState
<=
NeedingFirstThumbImage
)
{
queryThumbImageInfoJson
();
}
}
KIO
::
SimpleJob
*
POTDElement
::
createJsonQueryJob
(
const
QString
&
property
,
const
QString
&
title
,
const
QList
<
QueryItem
>
&
otherQueryItems
)
{
QUrl
url
(
QStringLiteral
(
"https://en.wikipedia.org/w/api.php"
));
QUrlQuery
urlQuery
{
{
QStringLiteral
(
"action"
),
QStringLiteral
(
"query"
)},
{
QStringLiteral
(
"format"
),
QStringLiteral
(
"json"
)},
{
QStringLiteral
(
"prop"
),
property
},
{
QStringLiteral
(
"titles"
),
title
},
};
for
(
const
auto
&
item
:
otherQueryItems
)
{
urlQuery
.
addQueryItem
(
item
.
key
,
item
.
value
);
}
url
.
setQuery
(
urlQuery
);
auto
job
=
KIO
::
storedGet
(
url
,
KIO
::
NoReload
,
KIO
::
HideProgressInfo
);
KIO
::
Scheduler
::
setJobPriority
(
job
,
1
);
return
job
;
}
KIO
::
SimpleJob
*
POTDElement
::
createImagesJsonQueryJob
(
PageProtectionState
state
)
{
const
char
*
const
templatePagePrefix
=
(
state
==
ProtectedPage
)
?
"Template:POTD_protected/"
:
"Template:POTD/"
;
const
QString
templatePageName
=
QLatin1String
(
templatePagePrefix
)
+
mDate
.
toString
(
Qt
::
ISODate
);
const
QList
<
QueryItem
>
otherQueryItems
{
// TODO: unsure if formatversion is needed, used by https://www.mediawiki.org/wiki/API:Picture_of_the_day_viewer in October 2021
{
QStringLiteral
(
"formatversion"
),
QStringLiteral
(
"2"
)},
};
return
createJsonQueryJob
(
QStringLiteral
(
"images"
),
templatePageName
,
otherQueryItems
);
}
void
POTDElement
::
queryImagesJson
()
{
auto
queryImagesJob
=
createImagesJsonQueryJob
(
ProtectedPage
);
connect
(
queryImagesJob
,
&
KIO
::
SimpleJob
::
result
,
this
,
&
POTDElement
::
handleProtectedImagesJsonResponse
);
}
void
POTDElement
::
handleImagesJsonResponse
(
KJob
*
job
,
PageProtectionState
pageProtectionState
)
{
if
(
job
->
error
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": could not get POTD file name:"
<<
job
->
errorString
();
setLoadingFailed
();
return
;
}
auto
const
transferJob
=
static_cast
<
KIO
::
StoredTransferJob
*>
(
job
);
const
auto
json
=
QJsonDocument
::
fromJson
(
transferJob
->
data
());
const
auto
pageObject
=
json
.
object
().
value
(
QLatin1String
(
"query"
)).
toObject
().
value
(
QLatin1String
(
"pages"
)).
toArray
().
at
(
0
).
toObject
();
auto
missingIt
=
pageObject
.
find
(
QLatin1String
(
"missing"
));
if
((
missingIt
!=
pageObject
.
end
())
&&
missingIt
.
value
().
toBool
(
false
))
{
// fallback to unprotected variant in case there is no protected variant
if
(
pageProtectionState
==
ProtectedPage
)
{
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": protected page reported as missing, trying unprocteded now."
;
auto
queryImagesJob
=
createImagesJsonQueryJob
(
UnprotectedPage
);
connect
(
queryImagesJob
,
&
KIO
::
SimpleJob
::
result
,
this
,
&
POTDElement
::
handleUnprotectedImagesJsonResponse
);
return
;
}
// no POTD set
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": also unprotected page reported as missing, Seems no POTD is declared."
;
setLoadingFailed
();
return
;
}
const
auto
imageObject
=
pageObject
.
value
(
QLatin1String
(
"images"
)).
toArray
().
at
(
0
).
toObject
();
const
QString
imageFile
=
imageObject
.
value
(
QLatin1String
(
"title"
)).
toString
();
if
(
imageFile
.
isEmpty
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": missing images data in reply:"
<<
json
;
setLoadingFailed
();
return
;
}
// store data
mData
->
mPictureName
=
imageFile
;
mData
->
mState
=
NeedingBasicImageInfo
;
queryBasicImageInfoJson
();
}
void
POTDElement
::
handleUnprotectedImagesJsonResponse
(
KJob
*
job
)
{
handleImagesJsonResponse
(
job
,
UnprotectedPage
);
}
void
POTDElement
::
handleProtectedImagesJsonResponse
(
KJob
*
job
)
{
handleImagesJsonResponse
(
job
,
ProtectedPage
);
}
void
POTDElement
::
queryBasicImageInfoJson
()
{
const
QList
<
QueryItem
>
otherQueryItems
{
{
QStringLiteral
(
"iiprop"
),
QStringLiteral
(
"url|size|canonicaltitle"
)},
};
auto
queryBasicImageInfoJob
=
createJsonQueryJob
(
QStringLiteral
(
"imageinfo"
),
mData
->
mPictureName
,
otherQueryItems
);
connect
(
queryBasicImageInfoJob
,
&
KIO
::
SimpleJob
::
result
,
this
,
&
POTDElement
::
handleBasicImageInfoJsonResponse
);
}
void
POTDElement
::
handleBasicImageInfoJsonResponse
(
KJob
*
job
)
{
if
(
job
->
error
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": could not get POTD file name:"
<<
job
->
errorString
();
setLoadingFailed
();
return
;
}
auto
const
transferJob
=
static_cast
<
KIO
::
StoredTransferJob
*>
(
job
);
const
auto
json
=
QJsonDocument
::
fromJson
(
transferJob
->
data
());
const
auto
pagesObject
=
json
.
object
().
value
(
QLatin1String
(
"query"
)).
toObject
().
value
(
QLatin1String
(
"pages"
)).
toObject
();
const
auto
pageObject
=
pagesObject
.
isEmpty
()
?
QJsonObject
()
:
pagesObject
.
begin
()
->
toObject
();
const
auto
imageInfo
=
pageObject
.
value
(
QLatin1String
(
"imageinfo"
)).
toArray
().
at
(
0
).
toObject
();
const
QString
url
=
imageInfo
.
value
(
QLatin1String
(
"url"
)).
toString
();
if
(
url
.
isEmpty
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": missing imageinfo data in reply:"
<<
json
;
setLoadingFailed
();
return
;
}
const
QString
descriptionUrl
=
imageInfo
.
value
(
QLatin1String
(
"descriptionurl"
)).
toString
();
mData
->
mAboutPageUrl
=
QUrl
(
descriptionUrl
);
const
QString
description
=
imageInfo
.
value
(
QLatin1String
(
"canonicaltitle"
)).
toString
();
mData
->
mTitle
=
i18n
(
"Wikipedia POTD: %1"
,
description
);
const
int
width
=
imageInfo
.
value
(
QLatin1String
(
"width"
)).
toInt
();
const
int
height
=
imageInfo
.
value
(
QLatin1String
(
"height"
)).
toInt
();
mData
->
mPictureHWRatio
=
((
width
!=
0
)
&&
(
height
!=
0
))
?
height
/
static_cast
<
float
>
(
width
)
:
1.0
;
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": thumb width"
<<
width
<<
" thumb height"
<<
height
<<
"ratio"
<<
mData
->
mPictureHWRatio
;
mData
->
updateFetchedThumbSize
();
mData
->
mState
=
NeedingFirstThumbImageInfo
;
queryThumbImageInfoJson
();
}
void
POTDElement
::
queryThumbImageInfoJson
()
{
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": thumb size"
<<
mData
->
mThumbSize
<<
" adapted size"
<<
mData
->
mFetchedThumbSize
;
const
QList
<
QueryItem
>
otherQueryItems
{
{
QStringLiteral
(
"iiprop"
),
QStringLiteral
(
"url"
)},
{
QStringLiteral
(
"iiurlwidth"
),
QString
::
number
(
mData
->
mFetchedThumbSize
.
width
())},
{
QStringLiteral
(
"iiurlheight"
),
QString
::
number
(
mData
->
mFetchedThumbSize
.
height
())},
};
mQueryThumbImageInfoJob
=
createJsonQueryJob
(
QStringLiteral
(
"imageinfo"
),
mData
->
mPictureName
,
otherQueryItems
);
connect
(
mQueryThumbImageInfoJob
,
&
KIO
::
SimpleJob
::
result
,
this
,
&
POTDElement
::
handleThumbImageInfoJsonResponse
);
}
void
POTDElement
::
handleThumbImageInfoJsonResponse
(
KJob
*
job
)
{
mQueryThumbImageInfoJob
=
nullptr
;
if
(
job
->
error
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": could not get thumb info:"
<<
job
->
errorString
();
if
(
mData
->
mState
==
NeedingFirstThumbImageInfo
)
{
setLoadingFailed
();
}
return
;
}
auto
const
transferJob
=
static_cast
<
KIO
::
StoredTransferJob
*>
(
job
);
const
auto
json
=
QJsonDocument
::
fromJson
(
transferJob
->
data
());
auto
pagesObject
=
json
.
object
().
value
(
QLatin1String
(
"query"
)).
toObject
().
value
(
QLatin1String
(
"pages"
)).
toObject
();
auto
pageObject
=
pagesObject
.
isEmpty
()
?
QJsonObject
()
:
pagesObject
.
begin
()
->
toObject
();
auto
imageInfo
=
pageObject
.
value
(
QLatin1String
(
"imageinfo"
)).
toArray
().
at
(
0
).
toObject
();
const
QString
thumbUrl
=
imageInfo
.
value
(
QStringLiteral
(
"thumburl"
)).
toString
();
if
(
thumbUrl
.
isEmpty
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": missing imageinfo data in reply:"
<<
json
;
return
;
}
mData
->
mState
=
(
mData
->
mState
==
NeedingFirstThumbImageInfo
)
?
NeedingFirstThumbImage
:
NeedingNextThumbImage
;
getThumbImage
(
QUrl
(
thumbUrl
));
}
void
POTDElement
::
getThumbImage
(
const
QUrl
&
thumbUrl
)
{
if
(
mGetThumbImageJob
)
{
mGetThumbImageJob
->
kill
();
}
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": fetching POTD thumbnail:"
<<
thumbUrl
;
mGetThumbImageJob
=
KIO
::
storedGet
(
thumbUrl
,
KIO
::
NoReload
,
KIO
::
HideProgressInfo
);
KIO
::
Scheduler
::
setJobPriority
(
mGetThumbImageJob
,
1
);
connect
(
mGetThumbImageJob
,
&
KIO
::
SimpleJob
::
result
,
this
,
&
POTDElement
::
handleGetThumbImageResponse
);
}
void
POTDElement
::
handleGetThumbImageResponse
(
KJob
*
job
)
{
mGetThumbImageJob
=
nullptr
;
const
bool
isAboutFirstThumbImage
=
(
mData
->
mState
==
NeedingFirstThumbImage
);
if
(
job
->
error
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": could not get POTD thumb:"
<<
job
->
errorString
();
if
(
isAboutFirstThumbImage
)
{
setLoadingFailed
();
}
return
;
}
// Last step completed: we get the pixmap from the transfer job's data
auto
const
transferJob
=
static_cast
<
KIO
::
StoredTransferJob
*>
(
job
);
if
(
!
mData
->
mThumbnail
.
loadFromData
(
transferJob
->
data
()))
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": could not load POTD thumb data."
;
if
(
isAboutFirstThumbImage
)
{
setLoadingFailed
();
}
return
;
}
mData
->
mState
=
DataLoaded
;
if
(
isAboutFirstThumbImage
)
{
// update other properties
Q_EMIT
gotNewShortText
(
shortText
());
Q_EMIT
gotNewLongText
(
mData
->
mTitle
);
Q_EMIT
gotNewUrl
(
mData
->
mAboutPageUrl
);
}
if
(
!
mRequestedThumbSize
.
isNull
())
{
Q_EMIT
gotNewPixmap
(
mData
->
mThumbnail
.
scaled
(
mRequestedThumbSize
,
Qt
::
KeepAspectRatio
,
Qt
::
SmoothTransformation
));
}
}
void
POTDElement
::
setLoadingFailed
()
{
mData
->
mState
=
LoadingFailed
;
Q_EMIT
gotNewShortText
(
QString
());
Q_EMIT
gotNewLongText
(
QString
());
}
QString
POTDElement
::
shortText
()
const
{
return
(
mData
->
mState
>=
DataLoaded
)
?
i18n
(
"Picture Page"
)
:
(
mData
->
mState
>=
NeedingPageData
)
?
i18n
(
"Loading..."
)
:
QString
();
}
QString
POTDElement
::
longText
()
const
{
return
(
mData
->
mState
>=
DataLoaded
)
?
mData
->
mTitle
:
(
mData
->
mState
>=
NeedingPageData
)
?
i18n
(
"<qt>Loading <i>Picture of the Day</i>...</qt>"
)
:
QString
();
}
QUrl
POTDElement
::
url
()
const
{
return
(
mData
->
mState
>=
DataLoaded
)
?
mData
->
mAboutPageUrl
:
QUrl
();
}
QPixmap
POTDElement
::
newPixmap
(
const
QSize
&
size
)
{
mRequestedThumbSize
=
size
;
if
((
mData
->
mThumbSize
.
width
()
<
size
.
width
())
||
(
mData
->
mThumbSize
.
height
()
<
size
.
height
()))
{
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
mDate
<<
": called for a new pixmap size ("
<<
size
<<
"instead of"
<<
mData
->
mThumbSize
<<
", stored pixmap:"
<<
mData
->
mThumbnail
.
size
()
<<
")"
;
mData
->
mThumbSize
=
size
;
if
(
mData
->
mState
>=
NeedingFirstThumbImageInfo
)
{
mData
->
updateFetchedThumbSize
();
if
((
mData
->
mFetchedThumbSize
.
width
()
<
size
.
width
())
||
(
mData
->
mFetchedThumbSize
.
height
()
<
size
.
height
()))
{
// only if there is already an initial pixmap to show at least something,
// kill current update and trigger new delayed update
if
(
mData
->
mState
>=
DataLoaded
)
{
if
(
mQueryThumbImageInfoJob
)
{
mQueryThumbImageInfoJob
->
kill
();
mQueryThumbImageInfoJob
=
nullptr
;
}
if
(
mGetThumbImageJob
)
{
mGetThumbImageJob
->
kill
();
mGetThumbImageJob
=
nullptr
;
}
mData
->
mState
=
NeedingNextThumbImageInfo
;
}
// We start a new thumbnail download a little later; the following code
// is to avoid too frequent transfers e.g. when resizing
mThumbImageGetDelayTimer
->
start
();
}
}
}
/* else, either we already got a sufficiently big pixmap (stored in mData->mThumbnail),
or we will get one anytime soon (we are downloading it already) and we will
actualize what we return here later via gotNewPixmap */
if
(
mData
->
mThumbnail
.
isNull
())
{
return
QPixmap
();
}
return
mData
->
mThumbnail
.
scaled
(
mRequestedThumbSize
,
Qt
::
KeepAspectRatio
,
Qt
::
SmoothTransformation
);
}
korganizer/plugins/picoftheday/element.h
0 → 100644
View file @
12074996
/*
This file is part of KOrganizer.
SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
SPDX-FileCopyrightText: 2007 Loïc Corbasson <loic.corbasson@gmail.com>
SPDX-FileCopyrightText: 2021 Friedrich W. H. Kossebau <kossebau@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include
<EventViews/CalendarDecoration>
using
namespace
EventViews
::
CalendarDecoration
;
#include
<KIO/SimpleJob>
#include
<QUrl>
enum
DataState
{
LoadingFailed
=
-
1
,
NeedingPageData
=
0
,
NeedingBasicImageInfo
,
NeedingFirstThumbImageInfo
,
NeedingFirstThumbImage
,
DataLoaded
,
NeedingNextThumbImageInfo
,
NeedingNextThumbImage
,
};
struct
ElementData
{
float
mPictureHWRatio
=
1
;
QString
mPictureName
;
QUrl
mAboutPageUrl
;
QSize
mThumbSize
;
QSize
mFetchedThumbSize
;
QPixmap
mThumbnail
;
QString
mTitle
;
DataState
mState
=
NeedingPageData
;
void
updateFetchedThumbSize
();
};
class
POTDElement
:
public
Element
{
Q_OBJECT
public:
POTDElement
(
const
QString
&
id
,
QDate
date
,
ElementData
*
data
);
~
POTDElement
()
override
;
public:
// Element API
Q_REQUIRED_RESULT
QString
shortText
()
const
override
;
Q_REQUIRED_RESULT
QString
longText
()
const
override
;
Q_REQUIRED_RESULT
QUrl
url
()
const
override
;
Q_REQUIRED_RESULT
QPixmap
newPixmap
(
const
QSize
&
size
)
override
;
private:
void
queryImagesJson
();
void
queryBasicImageInfoJson
();
void
queryThumbImageInfoJson
();
void
getThumbImage
(
const
QUrl
&
thumbUrl
);
// POTD pages once decided about should get an edit-protected variant, but not all have that
enum
PageProtectionState
{
ProtectedPage
,
UnprotectedPage
};
KIO
::
SimpleJob
*
createImagesJsonQueryJob
(
PageProtectionState
pageProtectionState
);
struct
QueryItem
{
QString
key
;
QString
value
;
};
KIO
::
SimpleJob
*
createJsonQueryJob
(
const
QString
&
property
,
const
QString
&
title
,
const
QList
<
QueryItem
>
&
otherQueryItems
=
{});
void
handleImagesJsonResponse
(
KJob
*
job
,
PageProtectionState
pageProtectionState
);
void
setLoadingFailed
();
private
Q_SLOTS
:
void
handleProtectedImagesJsonResponse
(
KJob
*
job
);
void
handleUnprotectedImagesJsonResponse
(
KJob
*
job
);
void
handleBasicImageInfoJsonResponse
(
KJob
*
job
);
void
handleThumbImageInfoJsonResponse
(
KJob
*
job
);
void
handleGetThumbImageResponse
(
KJob
*
job
);
void
completeMissingData
();
private:
const
QDate
mDate
;
QSize
mRequestedThumbSize
;
ElementData
*
mData
;
QTimer
*
mThumbImageGetDelayTimer
=
nullptr
;
KIO
::
SimpleJob
*
mQueryThumbImageInfoJob
=
nullptr
;
KIO
::
SimpleJob
*
mGetThumbImageJob
=
nullptr
;
};
korganizer/plugins/picoftheday/picoftheday.cpp
View file @
12074996
...
...
@@ -2,26 +2,32 @@
This file is part of KOrganizer.
SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
SPDX-FileCopyrightText: 2007 Loïc Corbasson <loic.corbasson@gmail.com>
SPDX-FileCopyrightText: 2021 Friedrich W. H. Kossebau <kossebau@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include
"picoftheday.h"
#include
"configdialog.h"
#include
"element.h"
#include
"korganizer_picoftheday_plugin_debug.h"
#include
<KConfig>
#include
<KConfigGroup>
#include
<KIO/Scheduler>
#include
<KLocalizedString>
#include
<KPluginFactory>
#include
<Q
DomDocument
>
#include
<
chrono
>
#include
<Q
Cache
>
#include
<
QGlobalStatic
>
K_PLUGIN_FACTORY
(
PicofthedayFactory
,
registerPlugin
<
Picoftheday
>
();)
using
namespace
std
::
chrono_literals
;
// TODO: add also disc cache to avoid even more network traffic
using
Cache
=
QCache
<
QDate
,
ElementData
>
;
constexpr
int
cacheElementMaxSize
=
6
*
7
;
// rows by weekdays, a full gregorian month's view
Q_GLOBAL_STATIC_WITH_ARGS
(
Cache
,
s_cache
,
(
cacheElementMaxSize
))
// https://www.mediawiki.org/wiki/API:Picture_of_the_day_viewer
Picoftheday
::
Picoftheday
(
QObject
*
parent
,
const
QVariantList
&
args
)
:
Decoration
(
parent
,
args
)
...
...
@@ -48,290 +54,27 @@ Element::List Picoftheday::createDayElements(const QDate &date)
{
Element
::
List
elements
;
auto
element
=
new
POTDElement
(
QStringLiteral
(
"main element"
),
date
,
mThumbSize
);
elements
.
append
(
element
);
return
elements
;
}
////////////////////////////////////////////////////////////////////////////////
POTDElement
::
POTDElement
(
const
QString
&
id
,
QDate
date
,
QSize
initialThumbSize
)
:
StoredElement
(
id
)
,
mDate
(
date
)
,
mThumbSize
(
initialThumbSize
)
{
setShortText
(
i18n
(
"Loading..."
));
setLongText
(
i18n
(
"<qt>Loading <i>Picture of the Day</i>...</qt>"
));
mTimer
=
new
QTimer
(
this
);
mTimer
->
setSingleShot
(
true
);
step1StartDownload
();
}
/** First step of three in the download process */
void
POTDElement
::
step1StartDownload
()
{
// Start downloading the picture
if
(
!
mFirstStepCompleted
&&
!
mFirstStepJob
)
{
QUrl
url
=
QUrl
(
QStringLiteral
(
"https://en.wikipedia.org/w/index.php?title=Template:POTD_protected/"
)
+
mDate
.
toString
(
Qt
::
ISODate
)
+
QStringLiteral
(
"&action=raw"
));
// The file at that URL contains the file name for the POTD
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
"step1StartDownload url :"
<<
url
;
mFirstStepJob
=
KIO
::
storedGet
(
url
,
KIO
::
NoReload
,
KIO
::
HideProgressInfo
);
KIO
::
Scheduler
::
setJobPriority
(
mFirstStepJob
,
1
);
connect
(
mFirstStepJob
,
&
KIO
::
SimpleJob
::
result
,
this
,
&
POTDElement
::
step1Result
);
connect
(
this
,
&
POTDElement
::
step1Success
,
this
,
&
POTDElement
::
step2GetImagePage
);
auto
data
=
s_cache
->
take
(
date
);
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
date
<<
": taking from cache"
<<
data
;
if
(
!
data
)
{
data
=
new
ElementData
;
data
->
mThumbSize
=
mThumbSize
;
}
}
/**
Give it a job which fetched the raw page,
and it'll give you the image file name hiding in it.
*/
void
POTDElement
::
step1Result
(
KJob
*
job
)
{
if
(
job
->
error
())
{
qCWarning
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
"POTD:"
<<
mDate
<<
": could not get POTD file name:"
<<
job
->
errorString
();
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
"POTD:"
<<
mDate
<<
": file name:"
<<
mFileName
;
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
"POTD:"
<<
mDate
<<
": full-size image:"
<<
mFullSizeImageUrl
;
qCDebug
(
KORGANIZERPICOFTHEDAYPLUGIN_LOG
)
<<
"POTD:"
<<
mDate
<<
": thumbnail:"
<<
mThumbUrl
;
mFirstStepCompleted
=
false
;
return
;
}
// First step completed: we now know the POTD's file name
auto
const
transferJob
=
static_cast
<
KIO
::
StoredTransferJob
*>
(
job
);
const
QStringList
lines
=
QString
::
fromUtf8
(
transferJob
->
data
().
data
(),
transferJob
->
data
().
size
()).
split
(
QLatin1Char
(
'\n'
));
for