Skip to content

Commit

Permalink
[script.timers] 4.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Heckie75 committed Sep 11, 2024
1 parent 4408c11 commit 0094bc0
Show file tree
Hide file tree
Showing 24 changed files with 876 additions and 265 deletions.
2 changes: 2 additions & 0 deletions script.timers/addon.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import migration
import service
from resources.lib.utils import housekeeper

if __name__ == "__main__":

migration.migrate()
housekeeper.cleanup_outdated_timers()
service.run()
16 changes: 8 additions & 8 deletions script.timers/addon.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.timers" name="Timers" version="3.9.3" provider-name="Heckie">
<addon id="script.timers" name="Timers" version="4.0.0" provider-name="Heckie">
<requires>
<import addon="xbmc.python" version="3.0.0" />
</requires>
<extension point="xbmc.service" library="addon.py" />
<extension point="xbmc.service" library="addon.py" />
<extension point="xbmc.python.script" library="script.py" />
<extension point="kodi.context.item">
<menu id="kodi.core.main">
Expand Down Expand Up @@ -66,6 +66,12 @@
<website>https://github.com/Heckie75/kodi-addon-timers</website>
<source>https://github.com/Heckie75/kodi-addon-timers</source>
<news>
v4.0.0 (2024-08-31)
- New Feature: programming timers with full date (not only day within upcoming 7 days, feature request #34)
- Improved stop behavior of overlapping media timers acc. its priority
- Bugfix / Workaround: [Kodi v21] Settings dialog is broken, issue #43
- Bugfix: [Kodi v21] Addon can't play PVR items anymore, issue #42

v3.9.3 (2024-08-02)
- Bugfix: Fixed that 'running-high-prio-fading-only-timer' prevents starting other media timers within its period

Expand All @@ -87,12 +93,6 @@ v3.7.0 (2023-06-30)
- If you stop explicitly playback while a start-stop-timer is running there won't be another stop action anymore when this timer runs out.
- Added workaround that streamed video (probably mpeg-dash) immediately stops after timer has started (only happened if 'seek to correct time if timer starts belatedly' is activated)

v3.6.0 (2023-04-16)
- Smart shuffle mode for slideshows (try randomly to find folder that fits into timeframe)
- Fixed resuming slideshow at right position
- Fixed resuming of enclosing timers especially combination of concurrent media types like video, audio or slideshow
- Improved notifications and competitive behavior (introduced extra low priority)

Complete changelog see https://github.com/Heckie75/kodi-addon-timers
</news>
<assets>
Expand Down
17 changes: 17 additions & 0 deletions script.timers/migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from resources.lib.timer.storage import Storage
from resources.lib.utils.settings_utils import (
activate_on_settings_changed_events, deactivate_on_settings_changed_events)
from resources.lib.utils.system_utils import get_kodi_version


def migrate_from_1_to_2(addon: xbmcaddon.Addon) -> int:
Expand Down Expand Up @@ -220,6 +221,18 @@ def migrate_from_6_to_7(addon: xbmcaddon.Addon) -> int:
return 7


def migrate_from_7_to_8(addon: xbmcaddon.Addon) -> int:

storage = Storage()
items = storage._load_from_storage()
for item in items:
item["date"] = ""

storage._save_to_storage(items)

return 8


def migrate() -> None:

addon = xbmcaddon.Addon()
Expand All @@ -246,6 +259,10 @@ def migrate() -> None:
if settingsVersion == 6:
settingsVersion = migrate_from_6_to_7(addon)

if settingsVersion == 7:
settingsVersion = migrate_from_7_to_8(addon)

addon.setSettingInt("settingsVersion", settingsVersion)
addon.setSettingInt("kodiVersion", int(get_kodi_version() * 100))

activate_on_settings_changed_events()
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ msgctxt "#32042"
msgid "from"
msgstr "von"

msgctxt "#32043"
msgid "specific date"
msgstr "spezifisches Datum"

msgctxt "#32044"
msgid "Date"
msgstr "Datum"

msgctxt "#32050"
msgid "This timer interrupts other timers"
msgstr "Dieser Timer unterbricht andere Timer"
Expand Down Expand Up @@ -526,12 +534,12 @@ msgid "Pause from"
msgstr "Pausiere von"

msgctxt "#32170"
msgid "Offset"
msgstr "Versatz"
msgid "Real-time clock"
msgstr "Zeitgeber"

msgctxt "#32171"
msgid "Offset for timers in seconds"
msgstr "Versatz für Timer in Sekunden"
msgid "Offset for real-time clock in seconds"
msgstr "Versatz für Zeitgeber in Sekunden"

msgctxt "#32180"
msgid "Presets for epg quick timer"
Expand All @@ -549,6 +557,22 @@ msgctxt "#32183"
msgid "always ask"
msgstr "jedes mal fragen"

msgctxt "#32190"
msgid "Housekeeping"
msgstr "Haushaltung"

msgctxt "#32191"
msgid "Cleanup missed timers at startup"
msgstr "Räume verpasste Timer beim Starten auf"

msgctxt "#32192"
msgid "Cleanup missed timers when Kodi starts. This can happen if Kodi was not running when timer has been scheduled."
msgstr "Räume verpasste Timer auf wenn Kodi gestartet wird. Das passiert, wenn Kodi nicht lief während ein Timer geplant war."

msgctxt "#32193"
msgid ""
msgstr ""

msgctxt "#32200"
msgid "Monday"
msgstr "Montag"
Expand Down Expand Up @@ -851,4 +875,8 @@ msgstr "Bestimme die Strategie für die Priorität neuer Quicktimer."

msgctxt "#32387"
msgid "Mediatype is normally determined automatically. Set type manually e.g. if resuming doesn't work as expected."
msgstr "Die Medienart wird automatisch ermittelt. Setze die Art manuell, z.B. wenn die Fortsetzung nicht richtig funktioniert."
msgstr "Die Medienart wird automatisch ermittelt. Setze die Art manuell, z.B. wenn die Fortsetzung nicht richtig funktioniert."

msgctxt "#32388"
msgid "Schedule this timer with full date and not only by day within one week."
msgstr "Programmiere diesen Timer zu einem Datum und nicht nur an einem Tag innerhalb einer Woche."
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ msgctxt "#32042"
msgid "from"
msgstr ""

msgctxt "#32043"
msgid "specific date"
msgstr ""

msgctxt "#32044"
msgid "Date"
msgstr ""

msgctxt "#32050"
msgid "This timer interrupts other timers"
msgstr ""
Expand Down Expand Up @@ -526,11 +534,11 @@ msgid "Pause from"
msgstr ""

msgctxt "#32170"
msgid "Offset"
msgid "Real-time clock"
msgstr ""

msgctxt "#32171"
msgid "Offset for timers in seconds"
msgid "Offset for real-time clock in seconds"
msgstr ""

msgctxt "#32180"
Expand All @@ -549,6 +557,22 @@ msgctxt "#32183"
msgid "always ask"
msgstr ""

msgctxt "#32190"
msgid "Housekeeping"
msgstr ""

msgctxt "#32191"
msgid "Cleanup missed timers at startup"
msgstr ""

msgctxt "#32192"
msgid "Cleanup missed timers when Kodi starts. This can happen if Kodi was not running when timer has been scheduled."
msgstr ""

msgctxt "#32193"
msgid ""
msgstr ""

msgctxt "#32200"
msgid "Monday"
msgstr ""
Expand Down Expand Up @@ -851,4 +875,8 @@ msgstr ""

msgctxt "#32387"
msgid "Mediatype is normally determined automatically. Set type manually e.g. if resuming doesn't work as expected."
msgstr ""
msgstr ""

msgctxt "#32388"
msgid "Schedule this timer with full date and not only by day within one week."
msgstr ""
60 changes: 45 additions & 15 deletions script.timers/resources/lib/contextmenu/abstract_set_timer.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import time
from datetime import datetime
from datetime import datetime, timedelta

import xbmc
import xbmcaddon
import xbmcgui
from resources.lib.contextmenu import pvr_utils
from resources.lib.player.mediatype import VIDEO, SCRIPT
from resources.lib.player.mediatype import SCRIPT, VIDEO
from resources.lib.timer.concurrency import determine_overlappings
from resources.lib.timer.storage import Storage
from resources.lib.timer.timer import (END_TYPE_DURATION, END_TYPE_NO,
Expand Down Expand Up @@ -58,6 +58,13 @@ def __init__(self, label: str, path: str, timerid=-1) -> None:
else:
timer.days = days

if timer.is_timer_by_date():
date = self.ask_date(timer.label, path, is_epg, timer)
if date == None:
return
else:
timer.set_timer_by_date(date)

starttime = self.ask_starttime(timer.label, path, is_epg, timer)
if starttime == None:
return
Expand All @@ -70,7 +77,7 @@ def __init__(self, label: str, path: str, timerid=-1) -> None:
else:
timer.duration = duration
timer.end = datetime_utils.format_from_seconds(
(datetime_utils.parse_time(starttime) + datetime_utils.parse_time(duration)).seconds)
(datetime_utils.parse_time(starttime) + datetime_utils.parse_time(duration)).total_seconds())

if is_epg:
timer.end_type = END_TYPE_TIME
Expand Down Expand Up @@ -103,8 +110,10 @@ def __init__(self, label: str, path: str, timerid=-1) -> None:
timer.vol_max = vol_max

timer.init()
now = datetime.today()
timer.to_timer_by_date(base=now)
overlappings = determine_overlappings(
timer, self.storage.load_timers_from_storage(), ignore_extra_prio=True)
timer, self.storage.load_timers_from_storage(), ignore_extra_prio=True, to_display=True, base=now)
if overlappings:
answer = self.handle_overlapping_timers(
timer, overlapping_timers=overlappings)
Expand All @@ -131,7 +140,7 @@ def is_supported(self, label: str, path: str) -> bool:
elif vfs_utils.is_pvr(path):
return vfs_utils.is_pvr_channel(path) or vfs_utils.is_pvr_recording(path) or xbmc.getCondVisibility("Window.IsVisible(tvguide)|Window.IsVisible(radioguide)")
else:
return vfs_utils.is_script(path) or vfs_utils.is_external(path) or not vfs_utils.is_folder(path) or vfs_utils.has_items_in_path(path)
return vfs_utils.is_script(path) or vfs_utils.is_audio_plugin(path) or vfs_utils.is_video_plugin(path) or vfs_utils.is_external(path) or not vfs_utils.is_folder(path) or vfs_utils.has_items_in_path(path)

def perform_ahead(self, timer: Timer) -> bool:

Expand All @@ -153,6 +162,14 @@ def ask_days(self, label: str, path: str, is_epg: bool, timer: Timer) -> 'list[i
else:
return [datetime.today().weekday()]

def ask_date(self, label: str, path: str, is_epg: bool, timer: Timer) -> str:

if is_epg:
return timer.date

else:
return datetime_utils.to_date_str(datetime.today())

def ask_starttime(self, label: str, path: str, is_epg: bool, timer: Timer) -> str:

if is_epg:
Expand Down Expand Up @@ -218,35 +235,48 @@ def _get_timer_preselection(self, timerid: int, label: str, path: str) -> 'tuple
timer.path = pvr_channel_path
startDate = datetime_utils.parse_xbmc_shortdate(
xbmc.getInfoLabel("ListItem.Date").split(" ")[0])
timer.days = [startDate.weekday()]
timer.start = xbmc.getInfoLabel("ListItem.StartTime")
duration = xbmc.getInfoLabel("ListItem.Duration")
if len(duration) == 5:
timer.duration = "00:%s" % duration[:2]

elif len(duration) == 9:
timer.set_timer_by_date(
date=datetime_utils.to_date_str(startDate))
start = datetime_utils.parse_time(
xbmc.getInfoLabel("ListItem.StartTime"))
timer.start, timer.start_offset = datetime_utils.format_from_timedelta(
start)

s_duration = xbmc.getInfoLabel("ListItem.Duration")
if len(s_duration) == 5:
s_duration = "00:%s" % s_duration[:2]

elif len(s_duration) == 9:
return None, False

else:
timer.duration = duration[:5]
s_duration = s_duration[:5]

td_duration = datetime_utils.parse_time(s_duration)
timer.duration, timer.duration_offset = datetime_utils.format_from_timedelta(
td_duration)

td_start = datetime_utils.parse_time(timer.start)
td_start = datetime_utils.parse_time(
timer.start) + timedelta(seconds=timer.start_offset)
if not is_epg:

if not timer.days or timer.days == [datetime_utils.WEEKLY]:
now = datetime_utils.DateTimeDelta.now()
timer.days.append(now.dt.weekday() if not td_start.seconds or td_start.seconds >
now.td.seconds else (now.dt.weekday() + 1) % 7)

timer.date = datetime_utils.to_date_str(now.dt)

if vfs_utils.is_favourites(path):
timer.path = vfs_utils.get_favourites_target(path)
else:
timer.path = path

timer.duration = timer.get_duration()

timer.end = datetime_utils.format_from_seconds(
(td_start + datetime_utils.parse_time(timer.duration)).seconds)
timer.end, timer.end_offset = datetime_utils.format_from_timedelta(
td_start + datetime_utils.parse_time(timer.duration) + timedelta(seconds=timer.duration_offset))

if vfs_utils.is_script(timer.path):
timer.media_type = SCRIPT
Expand Down
9 changes: 8 additions & 1 deletion script.timers/resources/lib/contextmenu/pvr_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import xbmc
from resources.lib.utils.jsonrpc_utils import json_rpc
from resources.lib.utils.system_utils import get_kodi_version

PVR_TV = "tv"
PVR_RADIO = "radio"
Expand All @@ -10,6 +11,9 @@
_WINDOW_RADIO_GUIDE = 10707

_PLAY_PVR_URL_PATTERN = "pvr://channels/%s/%s/%s_%i.pvr"
_PLAY_PVR_URL_PATTERN_V21 = "pvr://channels/%s/%s@%i/%i@%s_%i.pvr"

_CHANNEL_GROUP_ALL_ID = -1


def get_current_epg_view() -> str:
Expand Down Expand Up @@ -47,7 +51,10 @@ def get_pvr_channel_path(type: str, channelno: str) -> str:
== True and _c["clientid"] == channels[0]["clientid"]][0]

if channelGroupAll and pvrClient and channels[0]:
return _PLAY_PVR_URL_PATTERN % (type, parse.quote(channelGroupAll), pvrClient["addonid"], channels[0]["uniqueid"])
if get_kodi_version() < 21.0:
return _PLAY_PVR_URL_PATTERN % (type, parse.quote(channelGroupAll), pvrClient["addonid"], channels[0]["uniqueid"])
else:
return _PLAY_PVR_URL_PATTERN_V21 % (type, parse.quote(channelGroupAll), _CHANNEL_GROUP_ALL_ID, pvrClient["instanceid"], pvrClient["addonid"], channels[0]["uniqueid"])

except:
pass
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import xbmcgui
from resources.lib.contextmenu.abstract_set_timer import (CONFIRM_YES,
AbstractSetTimer)
from resources.lib.contextmenu.abstract_set_timer import AbstractSetTimer
from resources.lib.timer.concurrency import (ask_overlapping_timers,
get_next_higher_prio,
get_next_lower_prio)
from resources.lib.timer.timer import Timer
from resources.lib.utils.settings_utils import (CONFIRM_CUSTOM, CONFIRM_ESCAPE,
CONFIRM_NO, CONFIRM_YES,
from resources.lib.utils.settings_utils import (CONFIRM_CUSTOM, CONFIRM_YES,
trigger_settings_changed_event)


Expand All @@ -20,6 +18,7 @@ def perform_ahead(self, timer: Timer) -> bool:
for i, t in enumerate(timers):
if (found == -1
and timer.days == t.days
and timer.date == t.date
and timer.start == t.start
and timer.path == t.path):

Expand Down
Loading

0 comments on commit 0094bc0

Please sign in to comment.