riscritto service.py con schedule
This commit is contained in:
BIN
lib/python_libtorrent/linux_x86_64/1.1.1/libtorrent.so
Normal file
BIN
lib/python_libtorrent/linux_x86_64/1.1.1/libtorrent.so
Normal file
Binary file not shown.
617
lib/schedule.py
Normal file
617
lib/schedule.py
Normal file
@@ -0,0 +1,617 @@
|
||||
"""
|
||||
Python job scheduling for humans.
|
||||
|
||||
github.com/dbader/schedule
|
||||
|
||||
An in-process scheduler for periodic jobs that uses the builder pattern
|
||||
for configuration. Schedule lets you run Python functions (or any other
|
||||
callable) periodically at pre-determined intervals using a simple,
|
||||
human-friendly syntax.
|
||||
|
||||
Inspired by Addam Wiggins' article "Rethinking Cron" [1] and the
|
||||
"clockwork" Ruby module [2][3].
|
||||
|
||||
Features:
|
||||
- A simple to use API for scheduling jobs.
|
||||
- Very lightweight and no external dependencies.
|
||||
- Excellent test coverage.
|
||||
- Tested on Python 2.7, 3.5 and 3.6
|
||||
|
||||
Usage:
|
||||
>>> import schedule
|
||||
>>> import time
|
||||
|
||||
>>> def job(message='stuff'):
|
||||
>>> print("I'm working on:", message)
|
||||
|
||||
>>> schedule.every(10).minutes.do(job)
|
||||
>>> schedule.every(5).to(10).days.do(job)
|
||||
>>> schedule.every().hour.do(job, message='things')
|
||||
>>> schedule.every().day.at("10:30").do(job)
|
||||
|
||||
>>> while True:
|
||||
>>> schedule.run_pending()
|
||||
>>> time.sleep(1)
|
||||
|
||||
[1] https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/
|
||||
[2] https://github.com/Rykian/clockwork
|
||||
[3] https://adam.herokuapp.com/past/2010/6/30/replace_cron_with_clockwork/
|
||||
"""
|
||||
try:
|
||||
from collections.abc import Hashable
|
||||
except ImportError:
|
||||
from collections import Hashable
|
||||
import datetime
|
||||
import functools
|
||||
import logging
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
|
||||
logger = logging.getLogger('schedule')
|
||||
|
||||
|
||||
class ScheduleError(Exception):
|
||||
"""Base schedule exception"""
|
||||
pass
|
||||
|
||||
|
||||
class ScheduleValueError(ScheduleError):
|
||||
"""Base schedule value error"""
|
||||
pass
|
||||
|
||||
|
||||
class IntervalError(ScheduleValueError):
|
||||
"""An improper interval was used"""
|
||||
pass
|
||||
|
||||
|
||||
class CancelJob(object):
|
||||
"""
|
||||
Can be returned from a job to unschedule itself.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Scheduler(object):
|
||||
"""
|
||||
Objects instantiated by the :class:`Scheduler <Scheduler>` are
|
||||
factories to create jobs, keep record of scheduled jobs and
|
||||
handle their execution.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.jobs = []
|
||||
|
||||
def run_pending(self):
|
||||
"""
|
||||
Run all jobs that are scheduled to run.
|
||||
|
||||
Please note that it is *intended behavior that run_pending()
|
||||
does not run missed jobs*. For example, if you've registered a job
|
||||
that should run every minute and you only call run_pending()
|
||||
in one hour increments then your job won't be run 60 times in
|
||||
between but only once.
|
||||
"""
|
||||
runnable_jobs = (job for job in self.jobs if job.should_run)
|
||||
for job in sorted(runnable_jobs):
|
||||
self._run_job(job)
|
||||
|
||||
def run_all(self, delay_seconds=0):
|
||||
"""
|
||||
Run all jobs regardless if they are scheduled to run or not.
|
||||
|
||||
A delay of `delay` seconds is added between each job. This helps
|
||||
distribute system load generated by the jobs more evenly
|
||||
over time.
|
||||
|
||||
:param delay_seconds: A delay added between every executed job
|
||||
"""
|
||||
logger.info('Running *all* %i jobs with %is delay inbetween',
|
||||
len(self.jobs), delay_seconds)
|
||||
for job in self.jobs[:]:
|
||||
self._run_job(job)
|
||||
time.sleep(delay_seconds)
|
||||
|
||||
def clear(self, tag=None):
|
||||
"""
|
||||
Deletes scheduled jobs marked with the given tag, or all jobs
|
||||
if tag is omitted.
|
||||
|
||||
:param tag: An identifier used to identify a subset of
|
||||
jobs to delete
|
||||
"""
|
||||
if tag is None:
|
||||
del self.jobs[:]
|
||||
else:
|
||||
self.jobs[:] = (job for job in self.jobs if tag not in job.tags)
|
||||
|
||||
def cancel_job(self, job):
|
||||
"""
|
||||
Delete a scheduled job.
|
||||
|
||||
:param job: The job to be unscheduled
|
||||
"""
|
||||
try:
|
||||
self.jobs.remove(job)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def every(self, interval=1):
|
||||
"""
|
||||
Schedule a new periodic job.
|
||||
|
||||
:param interval: A quantity of a certain time unit
|
||||
:return: An unconfigured :class:`Job <Job>`
|
||||
"""
|
||||
job = Job(interval, self)
|
||||
return job
|
||||
|
||||
def _run_job(self, job):
|
||||
ret = job.run()
|
||||
if isinstance(ret, CancelJob) or ret is CancelJob:
|
||||
self.cancel_job(job)
|
||||
|
||||
@property
|
||||
def next_run(self):
|
||||
"""
|
||||
Datetime when the next job should run.
|
||||
|
||||
:return: A :class:`~datetime.datetime` object
|
||||
"""
|
||||
if not self.jobs:
|
||||
return None
|
||||
return min(self.jobs).next_run
|
||||
|
||||
@property
|
||||
def idle_seconds(self):
|
||||
"""
|
||||
:return: Number of seconds until
|
||||
:meth:`next_run <Scheduler.next_run>`.
|
||||
"""
|
||||
return (self.next_run - datetime.datetime.now()).total_seconds()
|
||||
|
||||
|
||||
class Job(object):
|
||||
"""
|
||||
A periodic job as used by :class:`Scheduler`.
|
||||
|
||||
:param interval: A quantity of a certain time unit
|
||||
:param scheduler: The :class:`Scheduler <Scheduler>` instance that
|
||||
this job will register itself with once it has
|
||||
been fully configured in :meth:`Job.do()`.
|
||||
|
||||
Every job runs at a given fixed time interval that is defined by:
|
||||
|
||||
* a :meth:`time unit <Job.second>`
|
||||
* a quantity of `time units` defined by `interval`
|
||||
|
||||
A job is usually created and returned by :meth:`Scheduler.every`
|
||||
method, which also defines its `interval`.
|
||||
"""
|
||||
def __init__(self, interval, scheduler=None):
|
||||
self.interval = interval # pause interval * unit between runs
|
||||
self.latest = None # upper limit to the interval
|
||||
self.job_func = None # the job job_func to run
|
||||
self.unit = None # time units, e.g. 'minutes', 'hours', ...
|
||||
self.at_time = None # optional time at which this job runs
|
||||
self.last_run = None # datetime of the last run
|
||||
self.next_run = None # datetime of the next run
|
||||
self.period = None # timedelta between runs, only valid for
|
||||
self.start_day = None # Specific day of the week to start on
|
||||
self.tags = set() # unique set of tags for the job
|
||||
self.scheduler = scheduler # scheduler to register with
|
||||
|
||||
def __lt__(self, other):
|
||||
"""
|
||||
PeriodicJobs are sortable based on the scheduled time they
|
||||
run next.
|
||||
"""
|
||||
return self.next_run < other.next_run
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
"Job(interval={}, "
|
||||
"unit={}, "
|
||||
"do={}, "
|
||||
"args={}, "
|
||||
"kwargs={})"
|
||||
).format(self.interval,
|
||||
self.unit,
|
||||
self.job_func.__name__,
|
||||
self.job_func.args,
|
||||
self.job_func.keywords)
|
||||
|
||||
def __repr__(self):
|
||||
def format_time(t):
|
||||
return t.strftime('%Y-%m-%d %H:%M:%S') if t else '[never]'
|
||||
|
||||
def is_repr(j):
|
||||
return not isinstance(j, Job)
|
||||
|
||||
timestats = '(last run: %s, next run: %s)' % (
|
||||
format_time(self.last_run), format_time(self.next_run))
|
||||
|
||||
if hasattr(self.job_func, '__name__'):
|
||||
job_func_name = self.job_func.__name__
|
||||
else:
|
||||
job_func_name = repr(self.job_func)
|
||||
args = [repr(x) if is_repr(x) else str(x) for x in self.job_func.args]
|
||||
kwargs = ['%s=%s' % (k, repr(v))
|
||||
for k, v in self.job_func.keywords.items()]
|
||||
call_repr = job_func_name + '(' + ', '.join(args + kwargs) + ')'
|
||||
|
||||
if self.at_time is not None:
|
||||
return 'Every %s %s at %s do %s %s' % (
|
||||
self.interval,
|
||||
self.unit[:-1] if self.interval == 1 else self.unit,
|
||||
self.at_time, call_repr, timestats)
|
||||
else:
|
||||
fmt = (
|
||||
'Every %(interval)s ' +
|
||||
('to %(latest)s ' if self.latest is not None else '') +
|
||||
'%(unit)s do %(call_repr)s %(timestats)s'
|
||||
)
|
||||
|
||||
return fmt % dict(
|
||||
interval=self.interval,
|
||||
latest=self.latest,
|
||||
unit=(self.unit[:-1] if self.interval == 1 else self.unit),
|
||||
call_repr=call_repr,
|
||||
timestats=timestats
|
||||
)
|
||||
|
||||
@property
|
||||
def second(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use seconds instead of second')
|
||||
return self.seconds
|
||||
|
||||
@property
|
||||
def seconds(self):
|
||||
self.unit = 'seconds'
|
||||
return self
|
||||
|
||||
@property
|
||||
def minute(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use minutes instead of minute')
|
||||
return self.minutes
|
||||
|
||||
@property
|
||||
def minutes(self):
|
||||
self.unit = 'minutes'
|
||||
return self
|
||||
|
||||
@property
|
||||
def hour(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use hours instead of hour')
|
||||
return self.hours
|
||||
|
||||
@property
|
||||
def hours(self):
|
||||
self.unit = 'hours'
|
||||
return self
|
||||
|
||||
@property
|
||||
def day(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use days instead of day')
|
||||
return self.days
|
||||
|
||||
@property
|
||||
def days(self):
|
||||
self.unit = 'days'
|
||||
return self
|
||||
|
||||
@property
|
||||
def week(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use weeks instead of week')
|
||||
return self.weeks
|
||||
|
||||
@property
|
||||
def weeks(self):
|
||||
self.unit = 'weeks'
|
||||
return self
|
||||
|
||||
@property
|
||||
def monday(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use mondays instead of monday')
|
||||
self.start_day = 'monday'
|
||||
return self.weeks
|
||||
|
||||
@property
|
||||
def tuesday(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use tuesdays instead of tuesday')
|
||||
self.start_day = 'tuesday'
|
||||
return self.weeks
|
||||
|
||||
@property
|
||||
def wednesday(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use wednesdays instead of wednesday')
|
||||
self.start_day = 'wednesday'
|
||||
return self.weeks
|
||||
|
||||
@property
|
||||
def thursday(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use thursdays instead of thursday')
|
||||
self.start_day = 'thursday'
|
||||
return self.weeks
|
||||
|
||||
@property
|
||||
def friday(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use fridays instead of friday')
|
||||
self.start_day = 'friday'
|
||||
return self.weeks
|
||||
|
||||
@property
|
||||
def saturday(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use saturdays instead of saturday')
|
||||
self.start_day = 'saturday'
|
||||
return self.weeks
|
||||
|
||||
@property
|
||||
def sunday(self):
|
||||
if self.interval != 1:
|
||||
raise IntervalError('Use sundays instead of sunday')
|
||||
self.start_day = 'sunday'
|
||||
return self.weeks
|
||||
|
||||
def tag(self, *tags):
|
||||
"""
|
||||
Tags the job with one or more unique indentifiers.
|
||||
|
||||
Tags must be hashable. Duplicate tags are discarded.
|
||||
|
||||
:param tags: A unique list of ``Hashable`` tags.
|
||||
:return: The invoked job instance
|
||||
"""
|
||||
if not all(isinstance(tag, Hashable) for tag in tags):
|
||||
raise TypeError('Tags must be hashable')
|
||||
self.tags.update(tags)
|
||||
return self
|
||||
|
||||
def at(self, time_str):
|
||||
"""
|
||||
Specify a particular time that the job should be run at.
|
||||
|
||||
:param time_str: A string in one of the following formats: `HH:MM:SS`,
|
||||
`HH:MM`,`:MM`, `:SS`. The format must make sense given how often
|
||||
the job is repeating; for example, a job that repeats every minute
|
||||
should not be given a string in the form `HH:MM:SS`. The difference
|
||||
between `:MM` and `:SS` is inferred from the selected time-unit
|
||||
(e.g. `every().hour.at(':30')` vs. `every().minute.at(':30')`).
|
||||
:return: The invoked job instance
|
||||
"""
|
||||
if (self.unit not in ('days', 'hours', 'minutes')
|
||||
and not self.start_day):
|
||||
raise ScheduleValueError('Invalid unit')
|
||||
if not isinstance(time_str, str):
|
||||
raise TypeError('at() should be passed a string')
|
||||
if self.unit == 'days' or self.start_day:
|
||||
if not re.match(r'^([0-2]\d:)?[0-5]\d:[0-5]\d$', time_str):
|
||||
raise ScheduleValueError('Invalid time format')
|
||||
if self.unit == 'hours':
|
||||
if not re.match(r'^([0-5]\d)?:[0-5]\d$', time_str):
|
||||
raise ScheduleValueError(('Invalid time format for'
|
||||
' an hourly job'))
|
||||
if self.unit == 'minutes':
|
||||
if not re.match(r'^:[0-5]\d$', time_str):
|
||||
raise ScheduleValueError(('Invalid time format for'
|
||||
' a minutely job'))
|
||||
time_values = time_str.split(':')
|
||||
if len(time_values) == 3:
|
||||
hour, minute, second = time_values
|
||||
elif len(time_values) == 2 and self.unit == 'minutes':
|
||||
hour = 0
|
||||
minute = 0
|
||||
_, second = time_values
|
||||
else:
|
||||
hour, minute = time_values
|
||||
second = 0
|
||||
if self.unit == 'days' or self.start_day:
|
||||
hour = int(hour)
|
||||
if not (0 <= hour <= 23):
|
||||
raise ScheduleValueError('Invalid number of hours')
|
||||
elif self.unit == 'hours':
|
||||
hour = 0
|
||||
elif self.unit == 'minutes':
|
||||
hour = 0
|
||||
minute = 0
|
||||
minute = int(minute)
|
||||
second = int(second)
|
||||
self.at_time = datetime.time(hour, minute, second)
|
||||
return self
|
||||
|
||||
def to(self, latest):
|
||||
"""
|
||||
Schedule the job to run at an irregular (randomized) interval.
|
||||
|
||||
The job's interval will randomly vary from the value given
|
||||
to `every` to `latest`. The range defined is inclusive on
|
||||
both ends. For example, `every(A).to(B).seconds` executes
|
||||
the job function every N seconds such that A <= N <= B.
|
||||
|
||||
:param latest: Maximum interval between randomized job runs
|
||||
:return: The invoked job instance
|
||||
"""
|
||||
self.latest = latest
|
||||
return self
|
||||
|
||||
def do(self, job_func, *args, **kwargs):
|
||||
"""
|
||||
Specifies the job_func that should be called every time the
|
||||
job runs.
|
||||
|
||||
Any additional arguments are passed on to job_func when
|
||||
the job runs.
|
||||
|
||||
:param job_func: The function to be scheduled
|
||||
:return: The invoked job instance
|
||||
"""
|
||||
self.job_func = functools.partial(job_func, *args, **kwargs)
|
||||
try:
|
||||
functools.update_wrapper(self.job_func, job_func)
|
||||
except AttributeError:
|
||||
# job_funcs already wrapped by functools.partial won't have
|
||||
# __name__, __module__ or __doc__ and the update_wrapper()
|
||||
# call will fail.
|
||||
pass
|
||||
self._schedule_next_run()
|
||||
self.scheduler.jobs.append(self)
|
||||
return self
|
||||
|
||||
@property
|
||||
def should_run(self):
|
||||
"""
|
||||
:return: ``True`` if the job should be run now.
|
||||
"""
|
||||
return datetime.datetime.now() >= self.next_run
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Run the job and immediately reschedule it.
|
||||
|
||||
:return: The return value returned by the `job_func`
|
||||
"""
|
||||
logger.info('Running job %s', self)
|
||||
ret = self.job_func()
|
||||
self.last_run = datetime.datetime.now()
|
||||
self._schedule_next_run()
|
||||
return ret
|
||||
|
||||
def _schedule_next_run(self):
|
||||
"""
|
||||
Compute the instant when this job should run next.
|
||||
"""
|
||||
if self.unit not in ('seconds', 'minutes', 'hours', 'days', 'weeks'):
|
||||
raise ScheduleValueError('Invalid unit')
|
||||
|
||||
if self.latest is not None:
|
||||
if not (self.latest >= self.interval):
|
||||
raise ScheduleError('`latest` is greater than `interval`')
|
||||
interval = random.randint(self.interval, self.latest)
|
||||
else:
|
||||
interval = self.interval
|
||||
|
||||
self.period = datetime.timedelta(**{self.unit: interval})
|
||||
self.next_run = datetime.datetime.now() + self.period
|
||||
if self.start_day is not None:
|
||||
if self.unit != 'weeks':
|
||||
raise ScheduleValueError('`unit` should be \'weeks\'')
|
||||
weekdays = (
|
||||
'monday',
|
||||
'tuesday',
|
||||
'wednesday',
|
||||
'thursday',
|
||||
'friday',
|
||||
'saturday',
|
||||
'sunday'
|
||||
)
|
||||
if self.start_day not in weekdays:
|
||||
raise ScheduleValueError('Invalid start day')
|
||||
weekday = weekdays.index(self.start_day)
|
||||
days_ahead = weekday - self.next_run.weekday()
|
||||
if days_ahead <= 0: # Target day already happened this week
|
||||
days_ahead += 7
|
||||
self.next_run += datetime.timedelta(days_ahead) - self.period
|
||||
if self.at_time is not None:
|
||||
if (self.unit not in ('days', 'hours', 'minutes')
|
||||
and self.start_day is None):
|
||||
raise ScheduleValueError(('Invalid unit without'
|
||||
' specifying start day'))
|
||||
kwargs = {
|
||||
'second': self.at_time.second,
|
||||
'microsecond': 0
|
||||
}
|
||||
if self.unit == 'days' or self.start_day is not None:
|
||||
kwargs['hour'] = self.at_time.hour
|
||||
if self.unit in ['days', 'hours'] or self.start_day is not None:
|
||||
kwargs['minute'] = self.at_time.minute
|
||||
self.next_run = self.next_run.replace(**kwargs)
|
||||
# If we are running for the first time, make sure we run
|
||||
# at the specified time *today* (or *this hour*) as well
|
||||
if not self.last_run:
|
||||
now = datetime.datetime.now()
|
||||
if (self.unit == 'days' and self.at_time > now.time() and
|
||||
self.interval == 1):
|
||||
self.next_run = self.next_run - datetime.timedelta(days=1)
|
||||
elif self.unit == 'hours' \
|
||||
and self.at_time.minute > now.minute \
|
||||
or (self.at_time.minute == now.minute
|
||||
and self.at_time.second > now.second):
|
||||
self.next_run = self.next_run - datetime.timedelta(hours=1)
|
||||
elif self.unit == 'minutes' \
|
||||
and self.at_time.second > now.second:
|
||||
self.next_run = self.next_run - \
|
||||
datetime.timedelta(minutes=1)
|
||||
if self.start_day is not None and self.at_time is not None:
|
||||
# Let's see if we will still make that time we specified today
|
||||
if (self.next_run - datetime.datetime.now()).days >= 7:
|
||||
self.next_run -= self.period
|
||||
|
||||
|
||||
# The following methods are shortcuts for not having to
|
||||
# create a Scheduler instance:
|
||||
|
||||
#: Default :class:`Scheduler <Scheduler>` object
|
||||
default_scheduler = Scheduler()
|
||||
|
||||
#: Default :class:`Jobs <Job>` list
|
||||
jobs = default_scheduler.jobs # todo: should this be a copy, e.g. jobs()?
|
||||
|
||||
|
||||
def every(interval=1):
|
||||
"""Calls :meth:`every <Scheduler.every>` on the
|
||||
:data:`default scheduler instance <default_scheduler>`.
|
||||
"""
|
||||
return default_scheduler.every(interval)
|
||||
|
||||
|
||||
def run_pending():
|
||||
"""Calls :meth:`run_pending <Scheduler.run_pending>` on the
|
||||
:data:`default scheduler instance <default_scheduler>`.
|
||||
"""
|
||||
default_scheduler.run_pending()
|
||||
|
||||
|
||||
def run_all(delay_seconds=0):
|
||||
"""Calls :meth:`run_all <Scheduler.run_all>` on the
|
||||
:data:`default scheduler instance <default_scheduler>`.
|
||||
"""
|
||||
default_scheduler.run_all(delay_seconds=delay_seconds)
|
||||
|
||||
|
||||
def clear(tag=None):
|
||||
"""Calls :meth:`clear <Scheduler.clear>` on the
|
||||
:data:`default scheduler instance <default_scheduler>`.
|
||||
"""
|
||||
default_scheduler.clear(tag)
|
||||
|
||||
|
||||
def cancel_job(job):
|
||||
"""Calls :meth:`cancel_job <Scheduler.cancel_job>` on the
|
||||
:data:`default scheduler instance <default_scheduler>`.
|
||||
"""
|
||||
default_scheduler.cancel_job(job)
|
||||
|
||||
|
||||
def next_run():
|
||||
"""Calls :meth:`next_run <Scheduler.next_run>` on the
|
||||
:data:`default scheduler instance <default_scheduler>`.
|
||||
"""
|
||||
return default_scheduler.next_run
|
||||
|
||||
|
||||
def idle_seconds():
|
||||
"""Calls :meth:`idle_seconds <Scheduler.idle_seconds>` on the
|
||||
:data:`default scheduler instance <default_scheduler>`.
|
||||
"""
|
||||
return default_scheduler.idle_seconds
|
||||
@@ -189,29 +189,7 @@ def get_all_settings_addon():
|
||||
|
||||
|
||||
def open_settings():
|
||||
settings_pre = get_all_settings_addon()
|
||||
__settings__.openSettings()
|
||||
settings_post = get_all_settings_addon()
|
||||
|
||||
from specials import videolibrary
|
||||
from platformcode import xbmc_videolibrary
|
||||
if settings_pre.get('downloadpath', None) != settings_post.get('downloadpath', None):
|
||||
xbmc_videolibrary.update_sources(settings_post.get('downloadpath', None), settings_pre.get('downloadpath', None))
|
||||
|
||||
# si se ha cambiado la ruta de la videoteca llamamos a comprobar directorios para que lo cree y pregunte
|
||||
# automaticamente si configurar la videoteca
|
||||
if settings_pre.get("videolibrarypath", None) != settings_post.get("videolibrarypath", None) or \
|
||||
settings_pre.get("folder_movies", None) != settings_post.get("folder_movies", None) or \
|
||||
settings_pre.get("folder_tvshows", None) != settings_post.get("folder_tvshows", None):
|
||||
videolibrary.move_videolibrary(settings_pre.get("videolibrarypath", None), settings_post.get("videolibrarypath", None),
|
||||
settings_pre.get("folder_movies", None), settings_post.get("folder_movies", None),
|
||||
settings_pre.get("folder_tvshows", None), settings_post.get("folder_tvshows", None))
|
||||
|
||||
# si se ha puesto que se quiere autoconfigurar y se había creado el directorio de la videoteca
|
||||
if not settings_pre.get("videolibrary_kodi", None) and settings_post.get("videolibrary_kodi", None):
|
||||
xbmc_videolibrary.ask_set_content(silent=True)
|
||||
elif settings_pre.get("videolibrary_kodi", None) and not settings_post.get("videolibrary_kodi", None):
|
||||
xbmc_videolibrary.clean()
|
||||
|
||||
|
||||
def get_setting(name, channel="", server="", default=None):
|
||||
|
||||
@@ -5928,7 +5928,7 @@ msgid "Logging"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#70789"
|
||||
msgid "* Change by opening the settings from KoD main menu"
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#70790"
|
||||
|
||||
@@ -5928,8 +5928,8 @@ msgid "Logging"
|
||||
msgstr "Logging"
|
||||
|
||||
msgctxt "#70789"
|
||||
msgid "* Change by opening the settings from KoD main menu"
|
||||
msgstr "* Cambia aprendo le impostazioni dal menu principale di KoD"
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#70790"
|
||||
msgid "RAR download in progress"
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
<setting id="folder_tvshows" type="text" label="70118" default="Serie TV"/>
|
||||
<setting id="folder_movies" type="text" label="70119" default="Film"/>
|
||||
<setting id="videolibrary_kodi" type="bool" label="70120" default="false"/>
|
||||
<setting id="settings_kod" type="action" label="70789" action=""/>
|
||||
<setting label="59997" type="lsep"/>
|
||||
<setting id="videolibrary_max_quality" type="bool" label="70729" default="false" visible="true"/>
|
||||
<setting id="next_ep" type="select" label="70746" lvalues="70752|70747|70748" default="0"/>
|
||||
@@ -95,7 +94,6 @@
|
||||
<category label="30153">
|
||||
<setting id="downloadenabled" type="bool" label="70689" default="false"/>
|
||||
<setting id="downloadpath" type="folder" label="30017" visible="eq(-1,true)" default="special://profile/addon_data/plugin.video.kod/downloads/" option="writeable"/>
|
||||
<setting id="settings_kod1" type="action" label="70789" action="" visible="eq(-2,true)"/>
|
||||
<!-- <setting id="library_add" type="bool" label="70230" default="false"/>
|
||||
<setting id="library_move" type="bool" label="70231" default="false" visible="eq(-1,true)" subsetting="true"/> -->
|
||||
<setting id="downloadlistpath" type="folder" label="30018" visible="eq(-3,true)" default="special://profile/addon_data/plugin.video.kod/downloads/list/" option="writeable"/>
|
||||
|
||||
810
service.py
810
service.py
@@ -1,426 +1,384 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Service for updating new episodes on library series
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import datetime, imp, math, threading, traceback, sys, glob, time
|
||||
|
||||
from platformcode import config
|
||||
try:
|
||||
import xbmc, os
|
||||
librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib'))
|
||||
sys.path.append(librerias)
|
||||
except:
|
||||
import os
|
||||
librerias = os.path.join(config.get_runtime_path(), 'lib')
|
||||
sys.path.append(librerias)
|
||||
|
||||
|
||||
from core import channeltools, filetools, videolibrarytools
|
||||
from platformcode import logger
|
||||
from platformcode import platformtools
|
||||
from specials import videolibrary
|
||||
from platformcode import updater
|
||||
|
||||
|
||||
def update(path, p_dialog, i, t, serie, overwrite):
|
||||
logger.info("Updating " + path)
|
||||
insertados_total = 0
|
||||
|
||||
head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo')
|
||||
# videolibrarytools.check_renumber_options(it)
|
||||
videolibrarytools.update_renumber_options(it, head_nfo, path)
|
||||
category = serie.category
|
||||
|
||||
# logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) ))
|
||||
for channel, url in serie.library_urls.items():
|
||||
serie.channel = channel
|
||||
serie.url = url
|
||||
|
||||
###### Redirección al canal NewPct1.py si es un clone, o a otro canal y url si ha intervención judicial
|
||||
try:
|
||||
head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo') #Refresca el .nfo para recoger actualizaciones
|
||||
if it.emergency_urls:
|
||||
serie.emergency_urls = it.emergency_urls
|
||||
serie.category = category
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
channel_enabled = channeltools.is_enabled(serie.channel)
|
||||
|
||||
if channel_enabled:
|
||||
|
||||
heading = config.get_localized_string(20000)
|
||||
p_dialog.update(int(math.ceil((i + 1) * t)), heading, config.get_localized_string(60389) % (serie.contentSerieName,
|
||||
serie.channel.capitalize()))
|
||||
try:
|
||||
pathchannels = filetools.join(config.get_runtime_path(), "channels", serie.channel + '.py')
|
||||
logger.info("Cargando canal: " + pathchannels + " " +
|
||||
serie.channel)
|
||||
|
||||
if serie.library_filter_show:
|
||||
serie.show = serie.library_filter_show.get(serie.channel, serie.contentSerieName)
|
||||
|
||||
obj = imp.load_source(serie.channel, pathchannels)
|
||||
itemlist = obj.episodios(serie)
|
||||
|
||||
try:
|
||||
if int(overwrite) == 3:
|
||||
# Sobrescribir todos los archivos (tvshow.nfo, 1x01.nfo, 1x01 [canal].json, 1x01.strm, etc...)
|
||||
insertados, sobreescritos, fallidos, notusedpath = videolibrarytools.save_tvshow(serie, itemlist)
|
||||
#serie= videolibrary.check_season_playcount(serie, serie.contentSeason)
|
||||
#if filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()):
|
||||
# serie.infoLabels['playcount'] = serie.playcount
|
||||
else:
|
||||
insertados, sobreescritos, fallidos = videolibrarytools.save_episodes(path, itemlist, serie,
|
||||
silent=True,
|
||||
overwrite=overwrite)
|
||||
#it = videolibrary.check_season_playcount(it, it.contentSeason)
|
||||
#if filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()):
|
||||
# serie.infoLabels['playcount'] = serie.playcount
|
||||
insertados_total += insertados
|
||||
|
||||
except Exception as ex:
|
||||
logger.error("Error al guardar los capitulos de la serie")
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
except Exception as ex:
|
||||
logger.error("Error al obtener los episodios de: %s" % serie.show)
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
else:
|
||||
logger.debug("Canal %s no activo no se actualiza" % serie.channel)
|
||||
|
||||
#Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa
|
||||
try:
|
||||
if config.is_xbmc(): #Si es Kodi, lo hacemos
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo')
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
return insertados_total > 0
|
||||
|
||||
|
||||
def check_for_update(overwrite=True):
|
||||
logger.info("Update Series...")
|
||||
p_dialog = None
|
||||
serie_actualizada = False
|
||||
update_when_finished = False
|
||||
hoy = datetime.date.today()
|
||||
estado_verify_playcount_series = False
|
||||
|
||||
try:
|
||||
if config.get_setting("update", "videolibrary") != 0 or overwrite:
|
||||
config.set_setting("updatelibrary_last_check", hoy.strftime('%Y-%m-%d'), "videolibrary")
|
||||
|
||||
heading = config.get_localized_string(60389)
|
||||
p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), heading)
|
||||
p_dialog.update(0, '')
|
||||
show_list = []
|
||||
|
||||
for path, folders, files in filetools.walk(videolibrarytools.TVSHOWS_PATH):
|
||||
show_list.extend([filetools.join(path, f) for f in files if f == "tvshow.nfo"])
|
||||
|
||||
if show_list:
|
||||
t = float(100) / len(show_list)
|
||||
|
||||
for i, tvshow_file in enumerate(show_list):
|
||||
head_nfo, serie = videolibrarytools.read_nfo(tvshow_file)
|
||||
path = filetools.dirname(tvshow_file)
|
||||
|
||||
logger.info("serie=" + serie.contentSerieName)
|
||||
p_dialog.update(int(math.ceil((i + 1) * t)), heading, serie.contentSerieName)
|
||||
|
||||
#Verificamos el estado del serie.library_playcounts de la Serie por si está incompleto
|
||||
try:
|
||||
estado = False
|
||||
#Si no hemos hecho la verificación o no tiene playcount, entramos
|
||||
estado = config.get_setting("verify_playcount", "videolibrary")
|
||||
if not estado or estado == False or not serie.library_playcounts: #Si no se ha pasado antes, lo hacemos ahora
|
||||
serie, estado = videolibrary.verify_playcount_series(serie, path) #También se pasa si falta un PlayCount por completo
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
else:
|
||||
if estado: #Si ha tenido éxito la actualización...
|
||||
estado_verify_playcount_series = True #... se marca para cambiar la opción de la Videoteca
|
||||
|
||||
interval = int(serie.active) # Podria ser del tipo bool
|
||||
|
||||
if not serie.active:
|
||||
# si la serie no esta activa descartar
|
||||
if not overwrite:
|
||||
#Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa, aunque la serie esté desactivada
|
||||
try:
|
||||
if config.is_xbmc(): #Si es Kodi, lo hacemos
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo')
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
continue
|
||||
|
||||
# obtenemos las fecha de actualizacion y de la proxima programada para esta serie
|
||||
update_next = serie.update_next
|
||||
if update_next:
|
||||
y, m, d = update_next.split('-')
|
||||
update_next = datetime.date(int(y), int(m), int(d))
|
||||
else:
|
||||
update_next = hoy
|
||||
|
||||
update_last = serie.update_last
|
||||
if update_last:
|
||||
y, m, d = update_last.split('-')
|
||||
update_last = datetime.date(int(y), int(m), int(d))
|
||||
else:
|
||||
update_last = hoy
|
||||
|
||||
# si la serie esta activa ...
|
||||
if overwrite or config.get_setting("updatetvshows_interval", "videolibrary") == 0:
|
||||
# ... forzar actualizacion independientemente del intervalo
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada:
|
||||
update_next = hoy + datetime.timedelta(days=interval)
|
||||
|
||||
elif interval == 1 and update_next <= hoy:
|
||||
# ...actualizacion diaria
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada and update_last <= hoy - datetime.timedelta(days=7):
|
||||
# si hace una semana q no se actualiza, pasar el intervalo a semanal
|
||||
interval = 7
|
||||
update_next = hoy + datetime.timedelta(days=interval)
|
||||
|
||||
elif interval == 7 and update_next <= hoy:
|
||||
# ...actualizacion semanal
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada:
|
||||
if update_last <= hoy - datetime.timedelta(days=14):
|
||||
# si hace 2 semanas q no se actualiza, pasar el intervalo a mensual
|
||||
interval = 30
|
||||
|
||||
update_next += datetime.timedelta(days=interval)
|
||||
|
||||
elif interval == 30 and update_next <= hoy:
|
||||
# ...actualizacion mensual
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada:
|
||||
update_next += datetime.timedelta(days=interval)
|
||||
|
||||
if serie_actualizada:
|
||||
update_last = hoy
|
||||
update_next = hoy + datetime.timedelta(days=interval)
|
||||
|
||||
head_nfo, serie = videolibrarytools.read_nfo(tvshow_file) #Vuelve a leer el.nfo, que ha sido modificado
|
||||
if interval != int(serie.active) or update_next.strftime('%Y-%m-%d') != serie.update_next or update_last.strftime('%Y-%m-%d') != serie.update_last:
|
||||
serie.update_last = update_last.strftime('%Y-%m-%d')
|
||||
if update_next > hoy:
|
||||
serie.update_next = update_next.strftime('%Y-%m-%d')
|
||||
serie.active = interval
|
||||
serie.channel = "videolibrary"
|
||||
serie.action = "get_seasons"
|
||||
filetools.write(tvshow_file, head_nfo + serie.tojson())
|
||||
|
||||
if serie_actualizada:
|
||||
if config.get_setting("search_new_content", "videolibrary") == 0:
|
||||
# Actualizamos la videoteca de Kodi: Buscar contenido en la carpeta de la serie
|
||||
if config.is_xbmc() and config.get_setting("videolibrary_kodi"):
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.update(folder=filetools.basename(path))
|
||||
else:
|
||||
update_when_finished = True
|
||||
|
||||
if estado_verify_playcount_series: #Si se ha cambiado algún playcount, ...
|
||||
estado = config.set_setting("verify_playcount", True, "videolibrary") #... actualizamos la opción de Videolibrary
|
||||
|
||||
if config.get_setting("search_new_content", "videolibrary") == 1 and update_when_finished:
|
||||
# Actualizamos la videoteca de Kodi: Buscar contenido en todas las series
|
||||
if config.is_xbmc() and config.get_setting("videolibrary_kodi"):
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.update()
|
||||
|
||||
p_dialog.close()
|
||||
|
||||
else:
|
||||
logger.info("No actualiza la videoteca, está desactivado en la configuración de alfa")
|
||||
|
||||
except Exception as ex:
|
||||
logger.error("Se ha producido un error al actualizar las series")
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
if p_dialog:
|
||||
p_dialog.close()
|
||||
|
||||
from core.item import Item
|
||||
item_dummy = Item()
|
||||
videolibrary.list_movies(item_dummy, silent=True)
|
||||
|
||||
|
||||
def start(thread=True):
|
||||
if thread:
|
||||
t = threading.Thread(target=start, args=[False])
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
else:
|
||||
import time
|
||||
|
||||
update_wait = [0, 10000, 20000, 30000, 60000]
|
||||
wait = update_wait[int(config.get_setting("update_wait", "videolibrary"))]
|
||||
if wait > 0:
|
||||
time.sleep(wait)
|
||||
|
||||
if not config.get_setting("update", "videolibrary") == 2:
|
||||
check_for_update(overwrite=False)
|
||||
|
||||
# Se ejecuta ciclicamente
|
||||
while True:
|
||||
monitor_update()
|
||||
time.sleep(3600) # cada hora
|
||||
|
||||
|
||||
def monitor_update():
|
||||
update_setting = config.get_setting("update", "videolibrary")
|
||||
|
||||
# "Actualizar "Una sola vez al dia" o "al inicar Kodi y al menos una vez al dia"
|
||||
|
||||
if update_setting == 2 or update_setting == 3:
|
||||
hoy = datetime.date.today()
|
||||
last_check = config.get_setting("updatelibrary_last_check", "videolibrary")
|
||||
if last_check:
|
||||
y, m, d = last_check.split('-')
|
||||
last_check = datetime.date(int(y), int(m), int(d))
|
||||
else:
|
||||
last_check = hoy - datetime.timedelta(days=1)
|
||||
|
||||
update_start = config.get_setting("everyday_delay", "videolibrary") * 4
|
||||
|
||||
# logger.info("Ultima comprobacion: %s || Fecha de hoy:%s || Hora actual: %s" %
|
||||
# (last_check, hoy, datetime.datetime.now().hour))
|
||||
# logger.info("Atraso del inicio del dia: %i:00" % update_start)
|
||||
|
||||
if last_check <= hoy and datetime.datetime.now().hour == int(update_start):
|
||||
logger.info("Inicio actualizacion programada para las %s h.: %s" % (update_start, datetime.datetime.now()))
|
||||
check_for_update(overwrite=False)
|
||||
|
||||
if not config.dev_mode():
|
||||
period = float(config.get_setting('addon_update_timer')) * 3600
|
||||
curTime = time.time()
|
||||
lastCheck = config.get_setting("updater_last_check", "videolibrary", '0')
|
||||
if lastCheck:
|
||||
lastCheck = float(lastCheck)
|
||||
else:
|
||||
lastCheck = 0
|
||||
|
||||
if curTime - lastCheck > period:
|
||||
updated, needsReload = updater.check(background=True)
|
||||
config.set_setting("updater_last_check", str(curTime), "videolibrary")
|
||||
if needsReload:
|
||||
xbmc.executescript(__file__)
|
||||
exit(0)
|
||||
|
||||
# always bypass al websites that use cloudflare at startup, so there's no need to wait 5 seconds when opened
|
||||
def callCloudflare():
|
||||
from core import httptools, support
|
||||
import json
|
||||
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
||||
channel_files = [os.path.splitext(os.path.basename(c))[0] for c in glob.glob(channels_path)]
|
||||
for channel_name in channel_files:
|
||||
channel_parameters = channeltools.get_channel_parameters(channel_name)
|
||||
if 'cloudflare' in channel_parameters and channel_parameters["cloudflare"]:
|
||||
channel = __import__('channels.%s' % channel_name, fromlist=["channels.%s" % channel_name])
|
||||
try:
|
||||
channel.findhost()
|
||||
except:
|
||||
pass
|
||||
httptools.downloadpage(channel.host)
|
||||
|
||||
servers_path = os.path.join(config.get_runtime_path(), "servers", '*.json')
|
||||
servers_files = glob.glob(servers_path)
|
||||
for server in servers_files:
|
||||
with open(server) as server:
|
||||
server_parameters = json.load(server)
|
||||
if 'cloudflare' in server_parameters and server_parameters["cloudflare"]:
|
||||
patternUrl = server_parameters["find_videos"]["patterns"][0]["url"]
|
||||
url = '/'.join(patternUrl.split('/')[:3])
|
||||
httptools.downloadpage(url)
|
||||
|
||||
|
||||
def viewmodeMonitor(monitor):
|
||||
import xbmcgui
|
||||
while not monitor.abortRequested():
|
||||
time.sleep(0.5)
|
||||
try:
|
||||
currentModeName = xbmc.getInfoLabel('Container.Viewmode')
|
||||
win = xbmcgui.Window(xbmcgui.getCurrentWindowId())
|
||||
currentMode = int(win.getFocusId())
|
||||
if currentModeName and 'plugin.video.kod' in xbmc.getInfoLabel('Container.FolderPath') and currentMode < 1000 and currentMode > 50: # inside addon and in itemlist view
|
||||
content, Type = platformtools.getCurrentView()
|
||||
defaultMode = int(config.get_setting('view_mode_%s' % content).split(',')[-1])
|
||||
if currentMode != defaultMode:
|
||||
logger.info('viewmode changed: ' + currentModeName + '-' + str(currentMode) + ' - content: ' + content)
|
||||
config.set_setting('view_mode_%s' % content, currentModeName + ', ' + str(currentMode))
|
||||
except:
|
||||
logger.error(traceback.print_exc())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# threading.Thread(target=callCloudflare())
|
||||
# Se ejecuta en cada inicio
|
||||
import xbmc
|
||||
import time
|
||||
|
||||
# mark as stopped all downloads (if we are here, probably kodi just started)
|
||||
from specials.downloads import stop_all
|
||||
stop_all()
|
||||
|
||||
update_wait = [0, 10000, 20000, 30000, 60000]
|
||||
wait = update_wait[int(config.get_setting("update_wait", "videolibrary"))]
|
||||
if wait > 0:
|
||||
xbmc.sleep(wait)
|
||||
|
||||
|
||||
# Verificar quick-fixes al abrirse Kodi, y dejarlo corriendo como Thread
|
||||
if not config.dev_mode():
|
||||
updated, needsReload = updater.check(background=True)
|
||||
config.set_setting("updater_last_check", str(time.time()), "videolibrary")
|
||||
if needsReload:
|
||||
xbmc.executescript(__file__)
|
||||
exit(0)
|
||||
|
||||
# Copia Custom code a las carpetas de Alfa desde la zona de Userdata
|
||||
# from platformcode import custom_code
|
||||
# custom_code.init()
|
||||
from threading import Thread
|
||||
Thread(target=viewmodeMonitor).start()
|
||||
from servers import torrent
|
||||
Thread(target=torrent.elementum_monitor).start()
|
||||
|
||||
if not config.get_setting("update", "videolibrary") == 2:
|
||||
check_for_update(overwrite=False)
|
||||
|
||||
|
||||
# Se ejecuta ciclicamente
|
||||
if config.get_platform(True)['num_version'] >= 14:
|
||||
monitor = xbmc.Monitor() # For Kodi >= 14
|
||||
else:
|
||||
monitor = None # For Kodi < 14
|
||||
|
||||
from threading import Thread
|
||||
|
||||
Thread(target=viewmodeMonitor, args=(monitor,)).start()
|
||||
|
||||
if monitor:
|
||||
while not monitor.abortRequested():
|
||||
monitor_update()
|
||||
if monitor.waitForAbort(3600): # cada hora
|
||||
break
|
||||
else:
|
||||
while not xbmc.abortRequested:
|
||||
monitor_update()
|
||||
xbmc.sleep(3600)
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
from platformcode import config
|
||||
librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib'))
|
||||
sys.path.insert(0, librerias)
|
||||
|
||||
from core import videolibrarytools, filetools, channeltools
|
||||
from lib import schedule
|
||||
from platformcode import logger, platformtools, updater
|
||||
from specials import videolibrary
|
||||
|
||||
|
||||
def update(path, p_dialog, i, t, serie, overwrite):
|
||||
logger.info("Updating " + path)
|
||||
insertados_total = 0
|
||||
|
||||
head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo')
|
||||
# videolibrarytools.check_renumber_options(it)
|
||||
videolibrarytools.update_renumber_options(it, head_nfo, path)
|
||||
category = serie.category
|
||||
|
||||
# logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) ))
|
||||
for channel, url in serie.library_urls.items():
|
||||
serie.channel = channel
|
||||
serie.url = url
|
||||
|
||||
###### Redirección al canal NewPct1.py si es un clone, o a otro canal y url si ha intervención judicial
|
||||
try:
|
||||
head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo') #Refresca el .nfo para recoger actualizaciones
|
||||
if it.emergency_urls:
|
||||
serie.emergency_urls = it.emergency_urls
|
||||
serie.category = category
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
channel_enabled = channeltools.is_enabled(serie.channel)
|
||||
|
||||
if channel_enabled:
|
||||
|
||||
heading = config.get_localized_string(20000)
|
||||
p_dialog.update(int(math.ceil((i + 1) * t)), heading, config.get_localized_string(60389) % (serie.contentSerieName,
|
||||
serie.channel.capitalize()))
|
||||
try:
|
||||
pathchannels = filetools.join(config.get_runtime_path(), "channels", serie.channel + '.py')
|
||||
logger.info("Cargando canal: " + pathchannels + " " +
|
||||
serie.channel)
|
||||
|
||||
if serie.library_filter_show:
|
||||
serie.show = serie.library_filter_show.get(serie.channel, serie.contentSerieName)
|
||||
|
||||
obj = __import__('channels.%s' % serie.channel, fromlist=[pathchannels])
|
||||
|
||||
itemlist = obj.episodios(serie)
|
||||
|
||||
try:
|
||||
if int(overwrite) == 3:
|
||||
# Sobrescribir todos los archivos (tvshow.nfo, 1x01.nfo, 1x01 [canal].json, 1x01.strm, etc...)
|
||||
insertados, sobreescritos, fallidos, notusedpath = videolibrarytools.save_tvshow(serie, itemlist)
|
||||
#serie= videolibrary.check_season_playcount(serie, serie.contentSeason)
|
||||
#if filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()):
|
||||
# serie.infoLabels['playcount'] = serie.playcount
|
||||
else:
|
||||
insertados, sobreescritos, fallidos = videolibrarytools.save_episodes(path, itemlist, serie,
|
||||
silent=True,
|
||||
overwrite=overwrite)
|
||||
#it = videolibrary.check_season_playcount(it, it.contentSeason)
|
||||
#if filetools.write(path + '/tvshow.nfo', head_nfo + it.tojson()):
|
||||
# serie.infoLabels['playcount'] = serie.playcount
|
||||
insertados_total += insertados
|
||||
|
||||
except Exception as ex:
|
||||
logger.error("Error al guardar los capitulos de la serie")
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
except Exception as ex:
|
||||
logger.error("Error al obtener los episodios de: %s" % serie.show)
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
else:
|
||||
logger.debug("Canal %s no activo no se actualiza" % serie.channel)
|
||||
|
||||
#Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa
|
||||
try:
|
||||
if config.is_xbmc(): #Si es Kodi, lo hacemos
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo')
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
return insertados_total > 0
|
||||
|
||||
|
||||
def check_for_update(overwrite=True):
|
||||
logger.info("Update Series...")
|
||||
p_dialog = None
|
||||
serie_actualizada = False
|
||||
update_when_finished = False
|
||||
hoy = datetime.date.today()
|
||||
estado_verify_playcount_series = False
|
||||
|
||||
try:
|
||||
if config.get_setting("update", "videolibrary") != 0 or overwrite:
|
||||
config.set_setting("updatelibrary_last_check", hoy.strftime('%Y-%m-%d'), "videolibrary")
|
||||
|
||||
heading = config.get_localized_string(60389)
|
||||
p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), heading)
|
||||
p_dialog.update(0, '')
|
||||
show_list = []
|
||||
|
||||
for path, folders, files in filetools.walk(videolibrarytools.TVSHOWS_PATH):
|
||||
show_list.extend([filetools.join(path, f) for f in files if f == "tvshow.nfo"])
|
||||
|
||||
if show_list:
|
||||
t = float(100) / len(show_list)
|
||||
|
||||
for i, tvshow_file in enumerate(show_list):
|
||||
head_nfo, serie = videolibrarytools.read_nfo(tvshow_file)
|
||||
path = filetools.dirname(tvshow_file)
|
||||
|
||||
logger.info("serie=" + serie.contentSerieName)
|
||||
p_dialog.update(int(math.ceil((i + 1) * t)), heading, serie.contentSerieName)
|
||||
|
||||
#Verificamos el estado del serie.library_playcounts de la Serie por si está incompleto
|
||||
try:
|
||||
estado = False
|
||||
#Si no hemos hecho la verificación o no tiene playcount, entramos
|
||||
estado = config.get_setting("verify_playcount", "videolibrary")
|
||||
if not estado or estado == False or not serie.library_playcounts: #Si no se ha pasado antes, lo hacemos ahora
|
||||
serie, estado = videolibrary.verify_playcount_series(serie, path) #También se pasa si falta un PlayCount por completo
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
else:
|
||||
if estado: #Si ha tenido éxito la actualización...
|
||||
estado_verify_playcount_series = True #... se marca para cambiar la opción de la Videoteca
|
||||
|
||||
interval = int(serie.active) # Podria ser del tipo bool
|
||||
|
||||
if not serie.active:
|
||||
# si la serie no esta activa descartar
|
||||
if not overwrite:
|
||||
#Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa, aunque la serie esté desactivada
|
||||
try:
|
||||
if config.is_xbmc(): #Si es Kodi, lo hacemos
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo')
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
continue
|
||||
|
||||
# obtenemos las fecha de actualizacion y de la proxima programada para esta serie
|
||||
update_next = serie.update_next
|
||||
if update_next:
|
||||
y, m, d = update_next.split('-')
|
||||
update_next = datetime.date(int(y), int(m), int(d))
|
||||
else:
|
||||
update_next = hoy
|
||||
|
||||
update_last = serie.update_last
|
||||
if update_last:
|
||||
y, m, d = update_last.split('-')
|
||||
update_last = datetime.date(int(y), int(m), int(d))
|
||||
else:
|
||||
update_last = hoy
|
||||
|
||||
# si la serie esta activa ...
|
||||
if overwrite or config.get_setting("updatetvshows_interval", "videolibrary") == 0:
|
||||
# ... forzar actualizacion independientemente del intervalo
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada:
|
||||
update_next = hoy + datetime.timedelta(days=interval)
|
||||
|
||||
elif interval == 1 and update_next <= hoy:
|
||||
# ...actualizacion diaria
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada and update_last <= hoy - datetime.timedelta(days=7):
|
||||
# si hace una semana q no se actualiza, pasar el intervalo a semanal
|
||||
interval = 7
|
||||
update_next = hoy + datetime.timedelta(days=interval)
|
||||
|
||||
elif interval == 7 and update_next <= hoy:
|
||||
# ...actualizacion semanal
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada:
|
||||
if update_last <= hoy - datetime.timedelta(days=14):
|
||||
# si hace 2 semanas q no se actualiza, pasar el intervalo a mensual
|
||||
interval = 30
|
||||
|
||||
update_next += datetime.timedelta(days=interval)
|
||||
|
||||
elif interval == 30 and update_next <= hoy:
|
||||
# ...actualizacion mensual
|
||||
serie_actualizada = update(path, p_dialog, i, t, serie, overwrite)
|
||||
if not serie_actualizada:
|
||||
update_next += datetime.timedelta(days=interval)
|
||||
|
||||
if serie_actualizada:
|
||||
update_last = hoy
|
||||
update_next = hoy + datetime.timedelta(days=interval)
|
||||
|
||||
head_nfo, serie = videolibrarytools.read_nfo(tvshow_file) #Vuelve a leer el.nfo, que ha sido modificado
|
||||
if interval != int(serie.active) or update_next.strftime('%Y-%m-%d') != serie.update_next or update_last.strftime('%Y-%m-%d') != serie.update_last:
|
||||
serie.update_last = update_last.strftime('%Y-%m-%d')
|
||||
if update_next > hoy:
|
||||
serie.update_next = update_next.strftime('%Y-%m-%d')
|
||||
serie.active = interval
|
||||
serie.channel = "videolibrary"
|
||||
serie.action = "get_seasons"
|
||||
filetools.write(tvshow_file, head_nfo + serie.tojson())
|
||||
|
||||
if serie_actualizada:
|
||||
if config.get_setting("search_new_content", "videolibrary") == 0:
|
||||
# Actualizamos la videoteca de Kodi: Buscar contenido en la carpeta de la serie
|
||||
if config.is_xbmc() and config.get_setting("videolibrary_kodi"):
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.update(folder=filetools.basename(path))
|
||||
else:
|
||||
update_when_finished = True
|
||||
|
||||
if estado_verify_playcount_series: #Si se ha cambiado algún playcount, ...
|
||||
estado = config.set_setting("verify_playcount", True, "videolibrary") #... actualizamos la opción de Videolibrary
|
||||
|
||||
if config.get_setting("search_new_content", "videolibrary") == 1 and update_when_finished:
|
||||
# Actualizamos la videoteca de Kodi: Buscar contenido en todas las series
|
||||
if config.is_xbmc() and config.get_setting("videolibrary_kodi"):
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.update()
|
||||
|
||||
p_dialog.close()
|
||||
|
||||
else:
|
||||
logger.info("No actualiza la videoteca, está desactivado en la configuración de alfa")
|
||||
|
||||
except Exception as ex:
|
||||
logger.error("Se ha producido un error al actualizar las series")
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
if p_dialog:
|
||||
p_dialog.close()
|
||||
|
||||
from core.item import Item
|
||||
item_dummy = Item()
|
||||
videolibrary.list_movies(item_dummy, silent=True)
|
||||
|
||||
|
||||
def viewmodeMonitor():
|
||||
try:
|
||||
currentModeName = xbmc.getInfoLabel('Container.Viewmode')
|
||||
win = xbmcgui.Window(xbmcgui.getCurrentWindowId())
|
||||
currentMode = int(win.getFocusId())
|
||||
if currentModeName and 'plugin.video.kod' in xbmc.getInfoLabel(
|
||||
'Container.FolderPath') and currentMode < 1000 and currentMode > 50: # inside addon and in itemlist view
|
||||
content, Type = platformtools.getCurrentView()
|
||||
defaultMode = int(config.get_setting('view_mode_%s' % content).split(',')[-1])
|
||||
if currentMode != defaultMode:
|
||||
logger.info('viewmode changed: ' + currentModeName + '-' + str(currentMode) + ' - content: ' + content)
|
||||
config.set_setting('view_mode_%s' % content, currentModeName + ', ' + str(currentMode))
|
||||
except:
|
||||
logger.error(traceback.print_exc())
|
||||
|
||||
|
||||
def updaterCheck():
|
||||
# updater check
|
||||
updated, needsReload = updater.check(background=True)
|
||||
if needsReload:
|
||||
xbmc.executescript(__file__)
|
||||
exit(0)
|
||||
|
||||
|
||||
def run_threaded(job_func, args):
|
||||
job_thread = threading.Thread(target=job_func, args=args)
|
||||
job_thread.start()
|
||||
|
||||
|
||||
class AddonMonitor(xbmc.Monitor):
|
||||
def __init__(self):
|
||||
self.settings_pre = config.get_all_settings_addon()
|
||||
|
||||
self.updaterPeriod = None
|
||||
self.update_setting = None
|
||||
self.update_hour = None
|
||||
self.scheduleUpdater()
|
||||
|
||||
# videolibrary wait
|
||||
update_wait = [0, 10000, 20000, 30000, 60000]
|
||||
wait = update_wait[int(config.get_setting("update_wait", "videolibrary"))]
|
||||
if wait > 0:
|
||||
xbmc.sleep(wait)
|
||||
if not config.get_setting("update", "videolibrary") == 2:
|
||||
check_for_update(overwrite=False)
|
||||
run_threaded(check_for_update, (False,))
|
||||
self.scheduleVideolibrary()
|
||||
super(AddonMonitor, self).__init__()
|
||||
|
||||
def onSettingsChanged(self):
|
||||
logger.info('settings changed')
|
||||
settings_post = config.get_all_settings_addon()
|
||||
from platformcode import xbmc_videolibrary
|
||||
|
||||
if self.settings_pre.get('downloadpath', None) != settings_post.get('downloadpath', None):
|
||||
xbmc_videolibrary.update_sources(settings_post.get('downloadpath', None),
|
||||
self.settings_pre.get('downloadpath', None))
|
||||
|
||||
# si se ha cambiado la ruta de la videoteca llamamos a comprobar directorios para que lo cree y pregunte
|
||||
# automaticamente si configurar la videoteca
|
||||
if self.settings_pre.get("videolibrarypath", None) != settings_post.get("videolibrarypath", None) or \
|
||||
self.settings_pre.get("folder_movies", None) != settings_post.get("folder_movies", None) or \
|
||||
self.settings_pre.get("folder_tvshows", None) != settings_post.get("folder_tvshows", None):
|
||||
videolibrary.move_videolibrary(self.settings_pre.get("videolibrarypath", None),
|
||||
settings_post.get("videolibrarypath", None),
|
||||
self.settings_pre.get("folder_movies", None),
|
||||
settings_post.get("folder_movies", None),
|
||||
self.settings_pre.get("folder_tvshows", None),
|
||||
settings_post.get("folder_tvshows", None))
|
||||
|
||||
# si se ha puesto que se quiere autoconfigurar y se había creado el directorio de la videoteca
|
||||
if not self.settings_pre.get("videolibrary_kodi", None) and settings_post.get("videolibrary_kodi", None):
|
||||
xbmc_videolibrary.ask_set_content(silent=True)
|
||||
elif self.settings_pre.get("videolibrary_kodi", None) and not settings_post.get("videolibrary_kodi", None):
|
||||
xbmc_videolibrary.clean()
|
||||
|
||||
if self.settings_pre.get('addon_update_timer') != settings_post.get('addon_update_timer'):
|
||||
schedule.clear('updater')
|
||||
self.scheduleUpdater()
|
||||
|
||||
if self.update_setting != config.get_setting("update", "videolibrary") or self.update_hour != config.get_setting("everyday_delay", "videolibrary") * 4:
|
||||
schedule.clear('videolibrary')
|
||||
self.scheduleVideolibrary()
|
||||
|
||||
self.settings_pre = settings_post
|
||||
|
||||
def onScreensaverActivated(self):
|
||||
logger.info('screensaver activated, un-scheduling screen-on jobs')
|
||||
schedule.clear('screenOn')
|
||||
|
||||
def onScreensaverDeactivated(self):
|
||||
logger.info('screensaver deactivated, re-scheduling screen-on jobs')
|
||||
schedule.every().second.do(viewmodeMonitor).tag('screenOn')
|
||||
|
||||
def scheduleUpdater(self):
|
||||
if not config.dev_mode():
|
||||
updaterCheck()
|
||||
self.updaterPeriod = float(config.get_setting('addon_update_timer')) * 3600
|
||||
schedule.every(self.updaterPeriod).hour.do(updaterCheck).tag('updater')
|
||||
logger.info('scheduled updater every ' + str(self.updaterPeriod) + ' hours')
|
||||
|
||||
def scheduleVideolibrary(self):
|
||||
self.update_setting = config.get_setting("update", "videolibrary")
|
||||
# 2= daily 3=daily and when kodi starts
|
||||
if self.update_setting == 2 or self.update_setting == 3:
|
||||
self.update_hour = config.get_setting("everyday_delay", "videolibrary") * 4
|
||||
schedule.every().day.at(str(self.update_hour).zfill(2) + ':00').do(run_threaded, check_for_update, (False,)).tag('videolibrary')
|
||||
logger.info('scheduled videolibrary at ' + str(self.update_hour).zfill(2) + ':00')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.info('Starting KoD service')
|
||||
monitor = AddonMonitor()
|
||||
|
||||
# mark as stopped all downloads (if we are here, probably kodi just started)
|
||||
from specials.downloads import stop_all
|
||||
stop_all()
|
||||
|
||||
# other things
|
||||
schedule.every().second.do(viewmodeMonitor).tag('screenOn')
|
||||
|
||||
while True:
|
||||
schedule.run_pending()
|
||||
|
||||
if monitor.waitForAbort(1): # every second
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user