248 lines
8.6 KiB
Python
248 lines
8.6 KiB
Python
#coding:utf-8
|
|
'''
|
|
|
|
Pierre Cadart
|
|
Script pour NAS sous Linux
|
|
|
|
Utilise un accès en FTP
|
|
|
|
'''
|
|
|
|
import posixpath
|
|
import re
|
|
import config
|
|
import piexel
|
|
import tokenizer
|
|
import filerule
|
|
from ftplib import FTP
|
|
import time
|
|
import file
|
|
|
|
|
|
def ftpwalk(directory, ftp):
|
|
"""
|
|
Parcours en profondeur un dossier du serveur FTP
|
|
Effectue un parcours préfixe,
|
|
semblable à la fonction os.walk
|
|
"""
|
|
to_visit = [directory]
|
|
while len(to_visit) > 0:
|
|
current = to_visit.pop(0)
|
|
ftp.cwd(current)
|
|
Lfiles = []
|
|
Ldirs = []
|
|
for name, prop in ftp.mlsd():
|
|
if name.startswith('.'):
|
|
continue
|
|
if prop['type'] == 'dir':
|
|
Ldirs.append(name)
|
|
to_visit.append(current+'/'+name)
|
|
elif prop['type'] == 'file':
|
|
Lfiles.append(name)
|
|
# ne construit pas la liste complète,
|
|
# mais retourne les résultats intermédiaires
|
|
yield (current, Ldirs, Lfiles)
|
|
|
|
def visit_folder(domain, api, rules, tok):
|
|
"""
|
|
Visite un dossier sur un serveur,
|
|
et ajoute les fichiers trouvés à l'API
|
|
"""
|
|
# Connection au serveur
|
|
print('connect to:', domain['server'])
|
|
ftp = FTP(domain['server'][6:], user=domain['username'], passwd=domain['password'])
|
|
ftp.encoding = 'UTF-8'
|
|
# Initialisation des listes de mises à jour
|
|
L_missing = [] # fichiers non trouvés sur le serveur FTP
|
|
L_unreferenced = [] # fichiers non référencés dans l'API
|
|
L_moved = [] # fichiers déplacés sur le serveur FTP
|
|
# Lecture des fichiers sur le serveur FTP
|
|
Lloc = []
|
|
for path, _, files in ftpwalk(domain['path'], ftp):
|
|
# Ajoute les fichiers correspondants aux extensions
|
|
for f in files:
|
|
match = filerule.match_rules(path+'/'+f, rules)
|
|
if match:
|
|
#print('got match:',match[1], 'name:',path+'/'+f)
|
|
F = file.File(path, f, match[1])
|
|
F.extract_title(tok)
|
|
Lloc.append(F)
|
|
ftp.close()
|
|
print('total:',len(Lloc))
|
|
# Récupère les fichiers de l'api
|
|
Lapi = []
|
|
for info in api.get_files(path=domain['server']+domain['path'], like=1, filable=1):
|
|
nfo = {}
|
|
if not info['filable']:
|
|
print('nfo:', info)
|
|
else:
|
|
year = int(info['filable']['release_date'][:4])
|
|
nfo['YEAR'] = year
|
|
F = file.File(info['path'][len(domain['server']):], info['name'], nfo, api_id=info['filable_id'])
|
|
F.extract_title(tok)
|
|
Lapi.append(F)
|
|
|
|
print('got api for ',domain['server']+domain['path'],':', len(Lapi))
|
|
#print('loc titles:', '|'.join(sorted([f.title for f in Lloc])))
|
|
#print('loc titles:', '|'.join(sorted([f.title for f in Lloc])))
|
|
#print('\n'*2)
|
|
#print('api titles:', '|'.join(sorted([f.title for f in Lapi])))
|
|
|
|
# supprime les dossiers de l'api (ils ne devraient pas apparaître)
|
|
Lapi = [f for f in Lapi if tok.conf.is_valid_file(f.name)]
|
|
|
|
# Compare avec la liste de l'api
|
|
Lmissing = [f for f in Lapi if f not in Lloc] # fichiers non présents localement
|
|
Lunref = [f for f in Lloc if f not in Lapi] # fichiers non référencés
|
|
|
|
# Fichiers déplacés localement
|
|
Lrelink = [] # liste des références à changer
|
|
for file1 in Lmissing:
|
|
for file2 in Lunref:
|
|
if file1.filename_same(file2):
|
|
Lrelink.append((file1, file2))
|
|
for fApi, fLoc in Lrelink:
|
|
Lmissing.remove(fApi)
|
|
Lunref.remove(fLoc)
|
|
print('moved:', Lrelink)
|
|
|
|
# Linke les fichiers identiques au même film
|
|
Llink = []
|
|
for file1 in Lunref:
|
|
for file2 in Lapi:
|
|
if file1.title == file2.title:
|
|
Llink.append((file1, file2.api_id))
|
|
print('D add:', file1, file2, file2.api_id)
|
|
break
|
|
print('doubles:', sorted(Llink, key=lambda f:str(f)))
|
|
for f, _ in Llink:
|
|
Lunref.remove(f)
|
|
|
|
# Linke les films par nom si possible
|
|
APIfilms = api.get_films()
|
|
API_alltitles = []
|
|
for f in APIfilms:
|
|
if f['title']:
|
|
t = f['title'].replace(' ','').lower()
|
|
if t not in [e[0] for e in API_alltitles]:
|
|
API_alltitles.append((t, f['id']))
|
|
if f['title_vo']:
|
|
t = f['title_vo'].replace(' ','').lower()
|
|
if t not in [e[0] for e in API_alltitles]:
|
|
API_alltitles.append((t, f['id']))
|
|
API_alltitles = [f for f in API_alltitles if len(f[0])>10]
|
|
Llink2 = []
|
|
for film in Lunref:
|
|
for title, fid in API_alltitles:
|
|
if title==film.title:
|
|
Llink2.append((film, fid))
|
|
break
|
|
#print(film, ' <-> ', [f for f in APIfilms if f['id']==fid][0]['title'])
|
|
|
|
print('easy ref:', sorted(Llink2, key=lambda f:str(f)))
|
|
for f, _ in Llink2:
|
|
Lunref.remove(f)
|
|
|
|
print('missing (', len(Lmissing), '):',[str(e.api_id)+':'+repr(e) for e in sorted(Lmissing, key=lambda e:repr(e))])
|
|
print('\n'*3)
|
|
print('unreferenced:','|'.join(str(f) for f in sorted(Lunref, key=lambda e:repr(e))))
|
|
print('\n'*3)
|
|
print('unreferenced titles:', '|'.join(sorted([f.title for f in Lunref])))
|
|
|
|
# Put les renommages / déplacements
|
|
i = 0
|
|
for filmApi, filmLoc in Lrelink:
|
|
i += 1
|
|
print('['+str(i)+'/'+str(len(Lrelink))+']'+'relink:', filmApi.title)
|
|
try:
|
|
api.debug_print = True
|
|
api.put_file(id=filmApi.api_id, path=domain['server']+filmLoc.path, name=filmLoc.name)
|
|
api.debug_print = False
|
|
time.sleep(1)
|
|
except Exception as e:
|
|
print(e)
|
|
print('film '+filmApi.title+' not edited')
|
|
raise Exception('end')
|
|
|
|
# Poste les ajouts de doubles
|
|
i = 0
|
|
for film, filmID in Llink:
|
|
i += 1
|
|
print('['+str(i)+'/'+str(len(Llink))+']'+'link:', film.title)
|
|
try:
|
|
api.debug_print = True
|
|
api.post_file(path=domain['server']+film.path, name=film.name, type='Film', type_id=filmID, **film.additional_info())
|
|
api.debug_print = False
|
|
time.sleep(1)
|
|
except Exception as e:
|
|
print(e)
|
|
print('film '+film.title+' not added')
|
|
raise Exception('end')
|
|
|
|
# Poste les ajouts de doubles plus complexes
|
|
i = 0
|
|
for film, filmID in Llink2:
|
|
i += 1
|
|
print('['+str(i)+'/'+str(len(Llink2))+']'+'link2:', film.title)
|
|
try:
|
|
api.debug_print = True
|
|
api.post_file(path=domain['server']+film.path, name=film.name, type='Film', type_id=filmID, **film.additional_info())
|
|
api.debug_print = False
|
|
time.sleep(1)
|
|
except Exception as e:
|
|
print(e)
|
|
print('film '+film.title+' not added')
|
|
raise Exception('end')
|
|
|
|
# Poste tout les films locaux
|
|
i = 0
|
|
for film in Lunref:
|
|
i += 1
|
|
print('['+str(i)+'/'+str(len(Lunref))+']'+'post:', film.title, str(film.info.get('YEAR')))
|
|
try:
|
|
posted = False
|
|
if 'YEAR' in film.info:
|
|
resp = api.post_film(title=film.title, year=film.info['YEAR'])
|
|
if "id" in resp:
|
|
print('post: path=',domain['server']+film.path)
|
|
resp = api.post_file(path=domain['server']+film.path, name=film.name, type='film', type_id=resp["id"])
|
|
posted = True
|
|
if not posted:
|
|
resp = api.post_film(title=film.title)
|
|
if "id" in resp:
|
|
resp = api.post_file(path=domain['server']+film.path, name=film.name, type='film', type_id=resp["id"])
|
|
|
|
print('response:', resp)
|
|
time.sleep(1)
|
|
except Exception as e:
|
|
print(e)
|
|
print('film '+film.title+' not posted')
|
|
raise Exception('end')
|
|
|
|
# Supprime les fichiers qui n'existent plus
|
|
for film in Lmissing:
|
|
i += 1
|
|
print('['+str(i)+'/'+str(len(Lmissing))+']'+'missing:', film)
|
|
try:
|
|
resp = api.delete_file(id=film.api_id)
|
|
except Exception as e:
|
|
print(e)
|
|
print('film '+film.title+' not posted')
|
|
raise Exception('end')
|
|
time.sleep(1)
|
|
print('visit finished')
|
|
|
|
def main():
|
|
conf = config.Config()
|
|
api = piexel.Piexel(conf.server, conf.app, conf.token)
|
|
tokens = tokenizer.Tokenizer(conf, api)
|
|
folders = api.get_folders()
|
|
rules = api.get_paths()
|
|
|
|
for fold in folders:
|
|
applicable = [filerule.FileRule(re.escape(fold['path'])+'\\/'+r['regex'], conf) for r in rules if int(r['indexer_folder_id']) == fold['id']]
|
|
visit_folder(fold, api, applicable, tokens)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|