Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scheduled update feature [WIP] [request feedback] #158

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions common/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import datetime
import re
from concurrent.futures import ThreadPoolExecutor
from timermanager import TimerManager

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
Expand Down Expand Up @@ -64,6 +65,7 @@ class gPotherSide:
def __init__(self):
self.core = None
self._checking_for_new_episodes = False
self.timermanager = TimerManager()

def initialize(self, progname):
assert self.core is None, 'Already initialized'
Expand Down Expand Up @@ -448,13 +450,13 @@ def provider_sort_key(p):
return p.priority

return [{
'label': provider.name,
'label': provider.unit_name,
'can_search': provider.kind == provider.PROVIDER_SEARCH
} for provider in sorted(registry.directory.select(select_provider), key=provider_sort_key, reverse=True)]

def get_directory_entries(self, provider, query):
def match_provider(p):
return p.name == provider
return p.unit_name == provider

for provider in registry.directory.select(match_provider):
return [{
Expand All @@ -467,6 +469,17 @@ def match_provider(p):

return []

def disable_scheduled_update(self):
if self.timermanager.timer_and_service_exist():
self.timermanager.deactivate_timer()

def set_scheduled_update(self, interval):
if not self.timermanager.timer_and_service_exist():
self.timermanager.write_service()
self.timermanager.write_timer(interval)
self.timermanager.activate_timer()
self.set_config_value("update.scheduled_interval", interval)


PILL_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="{height}" width="{width}"
Expand Down Expand Up @@ -607,3 +620,5 @@ def gpotherside_image_provider(image_id, requested_size):
get_directory_providers = gpotherside.get_directory_providers
get_directory_entries = gpotherside.get_directory_entries
show_podcast = gpotherside.show_podcast
disable_scheduled_update = gpotherside.disable_scheduled_update
set_scheduled_update = gpotherside.set_scheduled_update
43 changes: 43 additions & 0 deletions common/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from gpodder.api import core
from concurrent.futures import ThreadPoolExecutor
import logging
import dbus
import gettext
import argparse

parser = argparse.ArgumentParser(description='Background daemon/service for gpodder')
parser.add_argument('--dry-run', action="store_true", help='skip any actions')

args = parser.parse_args()

appname = "harbour-org.gpodder.sailfish"
lang_translations = gettext.translation('base', localedir='translations/py_gettext')
_ = lang_translations.gettext

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

logger.info("starting scheduled gpodder refresh")


def run_update():
gp_core = core.Core(progname=appname)
with ThreadPoolExecutor() as executor:
for p in gp_core.model.get_podcasts():
executor.submit(lambda p: p.update(), p)

gp_core.shutdown()


if not args.dry_run:
run_update()

bus = dbus.SessionBus(private=False)
notify = dbus.Interface(bus.get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications"),
'org.freedesktop.Notifications')
notify.Notify("GPodder", 200, "/usr/share/icons/hicolor/86x86/apps/%s.png" %appname,
_('gpodder.refresh_notification_title'),
_('gpodder.refresh_notification_body'),
["", "default", "", "app"],
{'x-nemo-preview-summary': _('gpodder.refresh_notification_title'),
'x-nemo-preview-body': _('gpodder.refresh_notification_body')}, -1)
62 changes: 62 additions & 0 deletions common/timermanager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import pathlib
import logging
import os
import subprocess

logger = logging.getLogger(__name__)


class TimerManager():
def __init__(self, unit_name="harbour-org.gpodder.sailfish",
unit_file_location=pathlib.Path.home().joinpath(".config/systemd/user/")):
self.unit_name = unit_name
self.prefix = unit_file_location
self.prefixpath = pathlib.Path(self.prefix)
if not self.prefixpath.exists():
raise NotADirectoryError("folder '%s' for local unit files does not exist!" % self.prefixpath.absolute())
self.timerfile = self.prefixpath.joinpath('%s.timer' % self.unit_name)
self.servicefile = self.prefixpath.joinpath('%s.service' % self.unit_name)

def timer_and_service_exist(self):
logger.debug(
"searching for systemd unit files: '%s' '%s'" % (self.timerfile.absolute(), self.servicefile.absolute()))
return self.timerfile.is_file() and self.servicefile.is_file()

def write_service(self):
self.remove_file(self.servicefile)
with open(self.servicefile, "w") as file:
file.write("""
[Unit]
Description=%s service
[Service]
WorkingDirectory=/usr/share/harbour-org.gpodder.sailfish/
ExecStart=/usr/bin/python3 /usr/share/harbour-org.gpodder.sailfish/service.py
""" % self.unit_name)

def write_timer(self, interval="*-*-* *:*:0"):
self.remove_file(self.timerfile)
with open(self.timerfile, "w") as file:
file.write("""
[Unit]
Description=Timer for %s

[Timer]
OnCalendar=%s
Persistent=true

[Install]
WantedBy=timers.target
""" % (self.unit_name, interval))

def remove_file(self, file):
if file.is_file():
logger.debug("servicefile existed, will overwrite!")
os.remove(file.absolute())

def activate_timer(self):
subprocess.run(["systemctl", "--user", "enable", "%s.timer" % self.unit_name])
subprocess.run(["systemctl", "--user", "restart", "%s.timer" % self.unit_name])

def deactivate_timer(self):
subprocess.run(["systemctl", "--user", "stop", "%s.timer" % self.unit_name])
subprocess.run(["systemctl", "--user", "disable", "%s.timer" % self.unit_name])
2 changes: 1 addition & 1 deletion gpodder-sailfish.pro
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ gpodder.files = gpodder-core/src/*
gpodder.path = $${DEPLOY_PATH}/
minidb.files = minidb/minidb.py
minidb.path = $${DEPLOY_PATH}/
mainpy.files = common/main.py
mainpy.files = common/*.py
mainpy.path = $${DEPLOY_PATH}/
podcastparser.files = podcastparser/podcastparser.py
podcastparser.path = $${DEPLOY_PATH}/
Expand Down
38 changes: 38 additions & 0 deletions qml/SettingsPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,26 @@ Page {
py.getConfig('limit.episodes', function (value) {
limit_episodes.value = value;
});
py.getConfig('update.scheduled_interval', function (value) {
if(value) settingsPage.automaticUpdateTime = value;
});
} else if (status === PageStatus.Deactivating) {
py.setConfig('plugins.youtube.api_key_v3', youtube_api_key_v3.text);
py.setConfig('limit.episodes', parseInt(limit_episodes.value));
youtube_api_key_v3.focus = false;
if(settingsPage.automaticUpdateTime){
py.call('main.set_scheduled_update',[settingsPage.automaticUpdateTime])
console.info("setting scheduled updater to:",settingsPage.automaticUpdateTime)
}
else{
py.call('main.disable_scheduled_update')
console.info("disabling scheduled updater")
}
}
}

property var automaticUpdateTime

SilicaFlickable {
id: settingsList
anchors.fill: parent
Expand Down Expand Up @@ -92,6 +105,31 @@ Page {
maximumValue: 1000
stepSize: 100
}

SectionHeader {
text: qsTr("Automatic Updates")
horizontalAlignment: Text.AlignHCenter
}

Label{
text: settingsPage.automaticUpdateTime
}

Button {
id: automatic_update_time
text: qsTr("Choose Time")
onClicked: {
var dialog = pageStack.push("Sailfish.Silica.TimePickerDialog", {
hour: 6,
minute: 0,
hourMode: DateTime.TwelveHours
})
dialog.accepted.connect(function() {
settingsPage.automaticUpdateTime = "*-*-* "+dialog.hour+":"+dialog.minute+":*"
})
}

}
}
}
}
14 changes: 14 additions & 0 deletions test/timermanager-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import unittest
import common.timermanager
import tempfile

class TimerManager(unittest.TestCase):
def test_service_creation(self):
t=common.timermanager.TimerManager(unit_file_location=tempfile.mkdtemp())
self.assertFalse(t.timer_and_service_exist())
t.write_service()
t.write_timer("*-*-* *:*:00")
self.assertTrue(t.timer_and_service_exist())

if __name__ == '__main__':
unittest.main()
22 changes: 16 additions & 6 deletions translations/harbour-org.gpodder.sailfish-bg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,35 +512,45 @@
<context>
<name>SettingsPage</name>
<message>
<location filename="../qml/SettingsPage.qml" line="53"/>
<location filename="../qml/SettingsPage.qml" line="66"/>
<source>About</source>
<translation>Относно</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="63"/>
<location filename="../qml/SettingsPage.qml" line="76"/>
<source>Settings</source>
<translation>Настройки</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="67"/>
<location filename="../qml/SettingsPage.qml" line="80"/>
<source>YouTube</source>
<translation>YouTube</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="73"/>
<location filename="../qml/SettingsPage.qml" line="86"/>
<source>API Key (v3)</source>
<translation>API ключ (v3)</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="82"/>
<location filename="../qml/SettingsPage.qml" line="95"/>
<source>Limits</source>
<translation>Ограничения</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="88"/>
<location filename="../qml/SettingsPage.qml" line="101"/>
<source>Maximum episodes per feed</source>
<translation>Максимален брой епизоди за RSS емисия</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="110"/>
<source>Automatic Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="120"/>
<source>Choose Time</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SleepTimerDialog</name>
Expand Down
22 changes: 16 additions & 6 deletions translations/harbour-org.gpodder.sailfish-de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,35 +512,45 @@
<context>
<name>SettingsPage</name>
<message>
<location filename="../qml/SettingsPage.qml" line="53"/>
<location filename="../qml/SettingsPage.qml" line="66"/>
<source>About</source>
<translation>Über</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="63"/>
<location filename="../qml/SettingsPage.qml" line="76"/>
<source>Settings</source>
<translation>Einstellungen</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="67"/>
<location filename="../qml/SettingsPage.qml" line="80"/>
<source>YouTube</source>
<translation>YouTube</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="73"/>
<location filename="../qml/SettingsPage.qml" line="86"/>
<source>API Key (v3)</source>
<translation>API Schlüssel (v3)</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="82"/>
<location filename="../qml/SettingsPage.qml" line="95"/>
<source>Limits</source>
<translation>Grenzen</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="88"/>
<location filename="../qml/SettingsPage.qml" line="101"/>
<source>Maximum episodes per feed</source>
<translation>Maximale Anzahl Episoden pro Feed</translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="110"/>
<source>Automatic Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/SettingsPage.qml" line="120"/>
<source>Choose Time</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SleepTimerDialog</name>
Expand Down
Loading