|
#!/usr/bin/env python3
# (c) 2016 Jesús Cea Avión - jcea@jcea.es
# This code is licensed under AGPLv3.
from collections import namedtuple
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import email.utils
import smtplib
import sqlite3
import os
from hashlib import sha256
import xml.etree.ElementTree as ET
import random
import cbor
import pickle
import paramiko
from datetime import datetime,timedelta
import time
import os.path, configparser
dirname = os.path.dirname(__file__)
config = configparser.ConfigParser()
config.read(os.path.join(dirname, 'config.ini'), encoding='utf-8')
remitente = config['PUBLISH']['email']
servidor_correo = config['PUBLISH']['servidor_correo']
puerto_servidor_correo = config['PUBLISH']['puerto_servidor_correo']
usuario_correo = config['PUBLISH']['usuario_correo']
clave_correo = config['PUBLISH']['clave_correo']
use_tls = config.getboolean('PUBLISH', 'use_tls')
class ya_publicados:
def __init__(self):
self.path = os.path.join(dirname, 'kodi.pickle')
with open(self.path, 'rb') as f:
#data = f.read().split()
#index_episodio, index_pelicula = map(int, data)
self._ya_publicados = pickle.load(f)
#self._ya_publicados = {
# 'index_series':index_episodio,
# 'index_peliculas':index_pelicula,
# 'series':{},
# 'peliculas':{}
# }
def responsable(self, url):
for path, user in [
('dav://XXX/XXXX/', 'jcea'),
('dav://XXX/XXXX/', 'jcea'),
('dav://XXX/XXXX/', 'XXXXXX'),
('dav://XXX/XXXX/', 'XXXXXX'),
]:
if url[:len(path)] == path:
return user
raise KeyError('No encontramos el responsable de ' + url)
def _tipo(self, thetvdb_id, imdb_id, temporada, episodio):
if not (bool(thetvdb_id) ^ bool(imdb_id)):
raise RuntimeError('Esto no debería pasar nunca')
if imdb_id:
return 'peliculas', imdb_id
elif thetvdb_id:
if not (temporada and episodio):
raise RuntimeError('Esto no debería pasar nunca')
return 'series', (thetvdb_id, int(temporada), int(episodio))
def ya_publicado(self, responsable=None,
thetvdb_id=None, temporada=None, episodio=None,
imdb_id=None):
tipo, id_ = self._tipo(thetvdb_id, imdb_id, temporada, episodio)
if responsable not in self._ya_publicados[tipo]:
return False
return id_ in self._ya_publicados[tipo][responsable]
def publicado(self, identificador, responsable=None,
thetvdb_id=None, temporada=None, episodio=None,
imdb_id=None):
tipo, id_ = self._tipo(thetvdb_id, imdb_id, temporada, episodio)
self._ya_publicados['index_' + tipo] = identificador
if responsable not in self._ya_publicados[tipo]:
self._ya_publicados[tipo][responsable] = set()
self._ya_publicados[tipo][responsable].add(id_)
self.save()
def index_episodio(self):
return self._ya_publicados['index_series']
def index_pelicula(self):
return self._ya_publicados['index_peliculas']
def save(self):
with open(self.path + '.NEW', 'wb') as f:
pickle.dump(self._ya_publicados, f, pickle.HIGHEST_PROTOCOL)
f.flush()
os.fsync(f.fileno())
os.rename(self.path + '.NEW', self.path)
ya_publicados = ya_publicados()
def envia_email(mensaje):
mensaje['From'] = remitente
mensaje['To'] = 'XXXXXX@XXXXXX'
mensaje['Date'] = email.utils.formatdate(localtime=True)
m = smtplib.SMTP(servidor_correo, puerto_servidor_correo)
m.ehlo()
if use_tls:
m.starttls()
m.ehlo() # Las capabilities pueden cambiar en TLS.
if sha256(m.sock.getpeercert(True)).hexdigest().lower() != \
'*********************************************' :
raise RuntimeError('El certificado digital del servidor de correo no coincide')
if usuario_correo:
m.login(usuario_correo, clave_correo)
m.sendmail(remitente, ['XXXXXX@XXXXXX'], mensaje.as_string())
comando = """
python3 -c 'import cbor,sqlite3,sys;
conn=sqlite3.connect("/home/osmc/.kodi/userdata/Database/MyVideos99.db");
capitulos=conn.execute("select
episode.idEpisode,episode.c00,episode.c01,episode.c06,episode.c12,episode.c13,episode.c18,tvshow.c00,tvshow.c01,tvshow.c06,tvshow.c10,tvshow.c12
from episode,tvshow where episode.idShow=tvshow.idShow and
episode.idEpisode>?",
({index_episodio:d},)).fetchall();
peliculas=conn.execute("select
idMovie,c00,c01,c02,c03,c04,c05,c06,c07,c08,c09,c11,c14,c15,c16,c19,c20,c22
from movie where idMovie>?",
({index_pelicula:d},)).fetchall();
set_peliculas = [str(i[0]) for i in peliculas];
casting=conn.execute("select
media_id, actor.name
from actor_link join actor using (actor_id)
where media_type=\\"movie\\" and media_id in (%s)
order by media_id,cast_order" % \",".join([\"?\"]*len(set_peliculas)),
set_peliculas).fetchall();
sys.stdout.buffer.write(cbor.dumps((capitulos,peliculas,casting)));'
""".replace('\n',' ').format(
index_episodio=ya_publicados.index_episodio(),
index_pelicula=ya_publicados.index_pelicula())
client = paramiko.client.SSHClient()
try:
client.load_system_host_keys()
with open('/home/jcea/.ssh/config') as f:
config = paramiko.config.SSHConfig()
config.parse(f)
osmcpi = config.lookup('osmcpi')
client.connect(osmcpi['hostname'], username=osmcpi['user'],
compress=True, timeout=30)
stdin, stdout, stderr = client.exec_command(comando, timeout=30)
err, out = b'', b''
while True:
if stdout.channel.recv_ready():
out += stdout.read()
if stderr.channel.recv_stderr_ready():
err += stderr.read()
if stdout.channel.exit_status_ready():
break
time.sleep(0.1)
if err:
raise RuntimeError('Error remoto: %s' %err)
respuesta = cbor.loads(out)
finally:
client.close()
episodio = namedtuple('episodio',
'identificador titulo resumen miniatura temporada episodio '
'url serie resumen_serie fanart epguide thetvdb')
pelicula = namedtuple('pelicula',
'identificador titulo resumen rresumen tagline '
'votos puntuacion guionista year miniaturas imdb '
'duracion genero director titulo_original trailer '
'fanart url')
capitulos, peliculas, casting = respuesta
for i in capitulos:
ep = episodio(*i)
index_episodio = ep.identificador
responsable = ya_publicados.responsable(ep.url)
subject = '(auto) STREAMING: %s: %dx%.2d %s [%s]' % (ep.serie,
int(ep.temporada), int(ep.episodio), ep.titulo, responsable)
print(ep.identificador, subject)
if ya_publicados.ya_publicado(
responsable=responsable,
thetvdb_id=ep.thetvdb,
temporada=ep.temporada,
episodio=ep.episodio):
print("Ya publicado")
continue
if input('¿Enviar? (y/N) ').lower() != 'y':
continue
url = 'https://thetvdb.com/?tab=series&lid=16&id=' + ep.thetvdb
texto = ep.resumen + '\n\n' + ep.serie + '\n'
texto += url + '\n' + ep.resumen_serie
plain = MIMEText(texto)
miniatura = ep.miniatura
miniatura = miniatura[miniatura.find('http'):miniatura.rfind('<')]
fanart = ET.fromstring('<?xml version="1.0"?><jcea>' + ep.fanart + '</jcea>')
fanart = [i.text for i in fanart.findall('./thumb[@aspect="banner"]')
if 'season' not in i.attrib]
if len(fanart):
fanart = '<p><img src="%s"/></p>' % random.choice(fanart)
else:
fanart = ''
texto = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>%s</title>
<style type="text/css">
body {margin: 0; padding: 0; min-width: 100%%!important;}
.content {width: 100%%; max-width: 600px;}
a {color: blue; text-decoration: none;}
a:hover {text-decoration: underline;}
</style>
</head>
<body>
<table width="100%%" border="0" cellpadding="0" cellspacing="0">
<img style="margin:1em;float:right;" src="%s"/>
%s
<h3 style="clear:both;"><a href="%s">%s</a></h3>
%s
%s
</table>
</body></html>
''' %(subject, miniatura, ep.resumen, url, ep.serie, ep.resumen_serie, fanart)
html = MIMEText(texto, 'html')
msg = MIMEMultipart('alternative')
msg.attach(plain)
msg.attach(html)
msg['Subject'] = subject
envia_email(msg)
ya_publicados.publicado(index_episodio,
responsable=responsable,
thetvdb_id=ep.thetvdb,
temporada=ep.temporada,
episodio=ep.episodio)
for i in peliculas:
peli = pelicula(*i)
index_pelicula = peli.identificador
responsable = ya_publicados.responsable(peli.url)
titulo = '%s (%s)' %(peli.titulo, peli.year)
subject = '(auto) STREAMING: %s [%s]' % (titulo, responsable)
print(peli.identificador, subject)
if ya_publicados.ya_publicado(
responsable=responsable,
imdb_id=peli.imdb):
print("Ya publicado")
continue
if input('¿Enviar? (y/N) ').lower() != 'y':
continue
miniaturas = ET.fromstring('<?xml version="1.0"?><jcea>' + peli.miniaturas + '</jcea>')
miniatura = ''
if len(miniaturas):
miniatura = miniaturas[0].get('preview')
if miniatura.startswith('http://assets.fanart.tv/fanart/') and \
miniatura.endswith('/preview'):
print("Reescribiendo URL de la imagen")
miniatura = \
miniatura[len('http://assets.fanart.tv/fanart/'):-len('/preview')]
miniatura = 'http://assets.fanart.tv/preview/' + miniatura
miniatura = '<img style="margin:1em;float:right;" src="%s"/>' % miniatura
trailer_prefix = 'plugin://plugin.video.youtube/?action=play_video&videoid='
trailer = ''
if peli.trailer.startswith(trailer_prefix):
trailer = '<a href="https://www.youtube.com/watch?v=%s">' \
'<img style="float:right; height:3.4em;' \
'margin-left:0.5em;" src="http://findicons.com/files/' \
'icons/51/capital_suite/113/film_reel.png"/></a>' % \
peli.trailer[len(trailer_prefix):]
actores = ', '.join((i[1] for i in casting if i[0]==index_pelicula))
t = datetime(1, 1, 1) + timedelta(seconds=int(peli.duracion))
duracion = '%d:%0.2d:%0.2d' % (t.hour, t.minute, t.second)
url = 'http://www.imdb.com/title/%s/' % peli.imdb
texto = '%s (%s)\n%s\n\n' %(peli.titulo, peli.year, peli.tagline)
texto += peli.rresumen + '\n\n' + peli.resumen + '\n\n'
texto += '%s\n%s\n' % (peli.titulo_original, url)
texto += 'Nota: %.1f/10 (%s votos)' % (float(peli.puntuacion), peli.votos)
texto += ' - Duración: %s\n' % duracion
texto += 'Director: %s\n' % peli.director
texto += 'Guionista: %s\n' % peli.guionista
texto += 'Género: %s\n' % peli.genero
texto += 'Actores: %s\n' % actores
plain = MIMEText(texto)
texto = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{titulo}</title>
<style type="text/css">
body {{margin: 0; padding: 0; min-width: 100%!important;}}
.content {{width: 100%; max-width: 600px;}}
a {{color: blue; text-decoration: none;}}
a:hover {{text-decoration: underline;}}
</style>
</head>
<body>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
{miniatura}
<div style="font-size: 120%"><b><a href="{url}">{titulo}</a></b></div>
<div style="font-size: 80%">{titulo_original}</div>
{trailer}
<p>{rresumen}</p>
<p>{resumen}</p>
<div style="background-color: #e0e0e0; font-style: italic;">
{titulo_original} ({year})
<br/><span style="font-size: 80%">{tagline}</span>
<br/><b>Nota:</b> {puntuacion:.1f}/10 ({votos} votos)
- <b>Duración:</b> {duracion}
<br/><b>Director:</b> {director}
<br/><b>Guionista:</b> {guionista}
<br/><b>Género:</b> {genero}
<br/><b>Actores:</b> {actores}
</div>
</table>
</body></html>
'''.format(titulo=titulo, miniatura=miniatura, url=url, tagline=peli.tagline,
rresumen=peli.rresumen, resumen=peli.resumen, trailer=trailer,
titulo_original=peli.titulo_original, year=peli.year,
director=peli.director, duracion=duracion,
puntuacion=float(peli.puntuacion), votos=peli.votos,
guionista=peli.guionista, genero=peli.genero, actores=actores)
html = MIMEText(texto, 'html')
msg = MIMEMultipart('alternative')
msg.attach(plain)
msg.attach(html)
msg['Subject'] = subject
envia_email(msg)
ya_publicados.publicado(index_pelicula,
responsable=responsable,
imdb_id=peli.imdb)
|