Progetto:Bot/Programmi in Python per i bot/uploader7.py

Da Wikisource.

Versione 07.07.15

Abilitata la chiamata via linea di comando

# -*- coding: cp1252 -*-
import pywikibot as wikipedia
import os,re,json,sys
from datetime import date
from urllib import FancyURLopener

'{{}}'


# dati obbligatori: data, autore, titolo, base, from, to

mesi=".gennaio.febbraio.marzo.aprile.maggio.giugno.luglio.agosto.settembre.ottobre.novembre.dicembre".split(".")


sito=wikipedia.Site("it","wikisource")
commons=wikipedia.Site("commons","commons")
class MyOpener(FancyURLopener):
    version = version = 'User-Agent: Alex (+http://it.wikisource.org/wiki/Utente:Alex_brollo)'
opener=MyOpener()

'''
Nuova versione: automazione integrale
Parametro unico: nome del File o dell'Indice
Flusso:
1. verificare se esiste il djvu in locale e eventualmente caricarlo
2. caricare la pagina Indice e estrarne tutti i dati con parseTemplate e eseguendo il parsing
   di pagelis e sommario
3. caricare la pagina Discussioni indice e caricare memoRegex e RigaIntestazione
4. caricare il testo delle pagine in nsPagina
4. creare la pagina principale in ns0
5. creare le altre sottopagine compreso tag pages provvisorio dai dati di Sommario
'''



# routine base
def carica(fileDjvu,ini=None,fin=None,sovrascrivi=False,\
           aggiustaParagrafi=False,test=False,soloNs0=False,piu_uno=True):
    if ini==None:
        ini=1
    # normalizzazione nome file
    fileDjvu=fileDjvu.replace(" ","_")

    #caricamento di tutti i dati

    #0 download del file djvu se non esistente
    commonsGrab("File:"+fileDjvu)
    
    #1 caricamento template Indice e eventuale caricamento del file djfu
    dati=caricaDatiIndice(fileDjvu)

    #2 lettura numero pagine
    numeroPag=numeroPagine(fileDjvu)
    if fin==None:
        fin=numeroPag
    #3 parsing sommario
    sommario=caricaSommario(dati[0]["Sommario"],numeroPag)

    #4 parsing pagelist
    pagelistDict=pagelist(dati[0]["Pagine"])

    #5 parsing memoRegex
    memoregex=caricaMemoregex(dati[1])

    #6 parsing schemi RigaIntestazione
    riList=caricaSchemi(dati[1])

    #7 loop creazione pagine
    if not soloNs0:
        for p in range(ini,fin):
            nomePagina="Pagina:"+fileDjvu+"/"+str(p)
            pagina=wikipedia.Page(sito,nomePagina)
            if pagina.exists() and not sovrascrivi:
                continue
            # preparazione comando djvuLibre
            comando="djvutxt -page=%numeroPagina %fileDjvu > pagina.utf"\
                  .replace("%numeroPagina",str(p))\
                  .replace("%fileDjvu",fileDjvu)
            #lancio comando
            os.system(comando)
            # elaborazione testo
            testo=unicode(open("pagina.utf").read(),"utf-8").replace(u"\x1f","")
            # qui aggiungere passi di elaborazione; il testo è unicode

            testo=djvutxtFix0(testo,aggiustaParagrafi)

            # esecuzione memoregex
            testo=eseguiMemoregex(testo,memoregex)
            
            #creazone rigaIntestazione
            ri=creaRi(p,pagelistDict,riList)

            #eliminazione testo rigaintestazione
            testo=testo.split("\n")
            if simil(testo[0].lower(),ri.lower(),2)>0.50:
                # print simil(testo[0].lower(),ri.lower(),2),ri, testo[0]
                testo=testo[1:]
            testo="\n".join(testo).strip()

            #aggiunta rigaintestazione
            header='<noinclude><pagequality level="1" user="Alebot" /><div class="pagetext">#ri#\n\n\n</noinclude>'.replace("#ri#",ri)
            footer='<noinclude></div>\n<references/></div></noinclude>'
            testo=header+testo+footer
            if not test:
                pagina.put(testo)
            else:
                print nomePagina
                print testo
    #8 loop creazione pagine ns0
    listaPagine=listaNs0(sommario)
    for i in range(len(listaPagine)):
        # se solopagina ha un valore continua se il valore non corrisponde
        # a listaPagine[i]
        
        pagina=wikipedia.Page(sito,listaPagine[i])
        if (not sovrascrivi):
            if pagina.exists():
                print "Pagina ",listaPagine[i], u" già esistente"
                continue
        #creaPagina(listaPagine[i])
        print "Lancio creazione di: ",listaPagine[i]
        
        # si ottiene qual+inclInt oppure qual+Intestazione, pages, from, to
        sottopagina=listaPagine[i].replace("_"," ")
        testoSottopagina=creaSottopagina(fileDjvu,sommario,sottopagina,dati,piu_uno)
        
        
        #
        if test:
            print testoSottopagina
        else:
            pagina.put(testoSottopagina)
        
    return


def listaNs0(sommario):
    l=[]

    for i in range(len(sommario)):
        stp=sommario[i]["nome"]
        if not stp in l:
            l.append(stp)
    l1=[]
    for i in range(len(l)):
        if len(l[i].split("/"))==1:
            l1.append(l[i])
    if len(l1)==0:
        l1.append(l[i].split("/")[0])
    for i in range(len(l)):
        if len(l[i].split("/"))>1:
            l1.append(l[i])
    return l1
    

def caricaDatiIndice(fileDjvu):
    rawIndice=wikipedia.Page(sito,"Indice:"+fileDjvu).get()
    print "Letti dati Indice:"+fileDjvu
    datiIndice=parseTemplate(rawIndice,":MediaWiki:Proofreadpage_index_template")[0]
    rawDiscussioniIndice='<inizio>1\t1000\t{{RigaIntestazione|999||}}\t{{RigaIntestazione|||999}}<fine>\n'+\
                          '{"c (.+)":["c (.+)","{{Centrato|$1}}","gm"]}'
    pdi=wikipedia.Page(sito,"Discussioni indice:"+fileDjvu)
    if pdi.exists():
        rawDiscussioniIndice=pdi.get()
        print "Letti dati Discussioni indice:"+fileDjvu
    else:
        print "Pagina Discussioni indice non esiste, creo valori di default"
    

    return (datiIndice,rawDiscussioniIndice)
    
  

def caricaMemoregex(testo):
    rls=find_stringa(testo,'\n{"','"]}',1)
    if rls=="":
        rls=ur'{"^c\\ (.+)":["^c\\ (.+)","{{Centrato|$1}}","gm"],"^ct (.+)":["^ct (.+)","{{Centrato|{{Type|$1}}}}","gm"]}'
    #print rls
    if rls !="":
        memoregex=json.loads(rls)
        for regex in memoregex:
                memoregex[regex][1]=memoregex[regex][1].replace("$1",r"\1")\
                              .replace("$2",r"\2").replace("$3",r"\3")
    return memoregex

def caricaSchemi(testo):
    schemi=find_stringa(testo,"<inizio>","<fine>",0)
    if schemi=="":
        schemi="1\t1000\t{{RigaIntestazione|999||}}\t{{RigaIntestazione|||999}}"
    riList=caricaRighe1(schemi)
    return riList
        
    



    


# costruisce RigaIntestazione per la pagina corrente
def creaRi(pagina,pagelistDict,riList):
    numeroPagina=pagelistDict[pagina]
    #print pagina,numeroPagina
    rigaIntestazione="{{RigaIntestazione|||}}"
    for i in range(len(riList)):
        if pagina>=int(riList[i][0]) and pagina<int(riList[i][1]):
            
            if isOdd(numeroPagina): # isOdd gstisce numeri, digitals e romani
                rigaIntestazione=riList[i][2]
            else:
                rigaIntestazione=riList[i][3]
            rigaIntestazione=rigaIntestazione.replace("999",str(numeroPagina))
            break
    return rigaIntestazione
        
# esegue memoRegex
def eseguiMemoregex(testo,memoregex):
    for i in memoregex:
        r=re.compile(memoregex[i][0])
        testo=re.sub(r,memoregex[i][1],testo)
    return testo

def caricaSommario(testoSommario,pagine):
    
    listaIndiceSommario=produci_lista(testoSommario,'{{Indice sommario','}}',1)
    sommario=[]
    for i in range(len(listaIndiceSommario)):
        dato=parseTemplate(listaIndiceSommario[i],"Indice sommario")[0]
        sommario.append(dato)
    for i in range(len(sommario)):
        try:
            sommario[i]["to"]=sommario[i+1]["from"]
        except:
            sommario[i]["to"]=str(pagine)
        

    return sommario

# restituisce il numero di pagine di un file djvu
def numeroPagine(fileDjvu):
    os.system('djvused -e "n" %fileDjvu>numeroPagine.utf'.replace("%fileDjvu",fileDjvu))
    np=int(open("numeroPagine.utf").read().strip())
    return np


def creaSottopagina(fileDjvu,sommario,pagina,dati,piu_uno):
    # crea template Qualità
    oggi=date.today()
    qual=u"{{Qualità|avz=25%|data=#data|arg=}}"
    qual=qual.replace("#data",str(oggi.day)+" "+mesi[int(oggi.month)]+" "+str(oggi.year))
    paginaBase=False
    if not "/" in pagina:
        paginaBase=True

    # sommario viene scorso alla ricerca dell'elemento pagina.
    # tre situazioni:
    # sottopagina;
    # pagina principale senza pagina titolo=Frontespizio;
    # pagina principale con pagina titolo=Frontespizio 
    
    for posizione in range(len(sommario)):
            if sommario[posizione]["nome"]==pagina or (paginaBase and sommario[posizione]["nome"]=="Frontespizio"):
                break
    # costruzione di IncludiIntestazione oppure di Intestazione
    
    if "/" in pagina: #sottopagina
        inclInt=u"{{IncludiIntestazione|sottotitolo=#sottotitolo|prec=#prec|succ=#succ}}"
        # pages=u'<pages index="#indice" from=#from to=#to fromsection= tosection= />
        

        # crea IncludiIntestazione
        
        prec=("" if posizione==0 else rel_atob(pagina,sommario[posizione-1]["nome"]))
        succ=("" if posizione==len(sommario)-1 else rel_atob(pagina,sommario[posizione+1]["nome"]))
        template=inclInt.replace("#sottotitolo",sommario[posizione]["titolo"])\
                 .replace("#prec",prec)\
                 .replace("#succ",succ)
        #pages=pages.replace("#from",sommario[posizione]["from"]).replace("#to",sommario[posizione]["to"]).replace("#indice",fileDjvu)                 
    else:
        schemaIntestazione=u'''{{Intestazione
| Nome e cognome dell'autore = #autore
| Titolo =#titolo
| Iniziale del titolo = 
| Anno di pubblicazione = #anno
| Lingua originale del testo = 
| Nome e cognome del traduttore = 
| Anno di traduzione =
| Progetto = #progetto
| Argomento = 
| URL della versione cartacea a fronte = Indice:#base
}}

'''
        template=schemaIntestazione.replace("#autore",dati[0]["Autore"])\
            .replace("#anno",dati[0]["Anno"])\
            .replace("#titolo",pagina)\
            .replace("#progetto",dati[0]["Progetto"])\
            .replace("#base",fileDjvu)
    pages='\n\n<pages index="#indice#" from=#from# to=#to# fromsection= tosection= />'\
           .replace("#indice#",fileDjvu)\
           .replace("#from#",sommario[posizione]["from"])
    if piu_uno:
        pages=pages.replace("#to#",sommario[posizione]["to"])
    else:
        pages=pages.replace("#to#",str(int(sommario[posizione]["to"])-1))
    
    return qual+template+pages



# esegue la post-elaborazione del testo
def djvutxtFix0(testo,aggiustaParagrafi):
    # pulizia scannos comuni
    testo=testo.replace(u"\x1d\x0b","")\
           .replace(u"\n\x1f\n\x0c","")\
           .replace(u"\x0c","")\
           .replace("\n\x1f","\n\n")\
           .replace("\n\nDigitized by ","")\
           .replace(u"\u2022",".")\
           .replace(" \n","\n")\
           .replace(" ,",",")\
           .replace(" .",".")\
           .replace(" ;",";")\
           .replace(" :",":")\
           .replace(u"¬","-")\
           .replace("\t"," ")\
           .replace("'",u"\u2019")
    #preOCR
    testo=testo.replace("{","(").replace("}",")")\
           .replace("<","").replace(">","")\
           .replace("[","(").replace("]",")")
           
        
    # eliminazione spazi a destra e a sinistra e stripping finale
    testo=testo.split("\n")
    for i in range(len(testo)):
        testo[i]=testo[i].strip()
    testo="\n".join(testo).strip()

    #dehyphenazione con salvataggio dell'eventuale ultimo hyphen
    testo=re.sub(ur"[-¬]\n([^ ]*)[ ]*[\n]?",ur"\1\n",testo)

    #aggiustamento paragrafi
    if aggiustaParagrafi:
        testo=testo.replace("\n\n","<fine paragrafo>")\
               .replace(".\n",".<fine paragrafo>")\
               .replace("?\n","?<fine paragrafo>")\
               .replace(":\n","!<fine paragrafo>")\
               .replace("!\n","!<fine paragrafo>")\
               .replace("\n"," ")\
               .replace("<fine paragrafo>","\n\n")
    return testo


# carica gli schemi e intervalli di RigaIntestazione
# si aspetta un file nomedjvu.ri
# pagina iniziale, pagina finale, rigaIntestazione pari, rigaIntestazione dispari
# separati da tabulazioni



def caricaRighe1(testo):
    ri=testo.split("\n")
    for i in range(len(ri)):
        ri[i]=ri[i].split("\t")
        ri[i][0]=int(ri[i][0])
        ri[i][1]=int(ri[i][1])
    return ri
# estrae dalla pagina Indice correlata al file djvu il codice pagelist
# e lo trasforma in un dizionario numero pagina djvu:numero pagina cartacea
def pagelist(pagine):
    
    codice=find_stringa(pagine,"<pagelist","/>",0).strip()
    
    r_to=re.compile(r"^to=(\d+)")
    r_from=re.compile(r"^from=(\d+)")
    r_1to1=re.compile(r"^(\d+)to(\d+)=(.+)")
    r_eq=re.compile(r"^(\d+)=(\d+)")
    r_eq1=re.compile(r"^(\d+)=([^0-9]+)")
    codice=codice.split()
    np=int(open("numeroPagine.utf").read().strip())
    paglist={}
    for i in range(1,np+1):
        paglist[i]=str(i)
    stili=[]
    for c in codice:
        if re.match(r_to,c): # caso tipo to=100
            #print c, "elemento tipo to="
            continue
        if re.match(r_from,c): # caso tipo from=100
            #print c, "elemento tipo from="
            continue
        if re.match(r_1to1,c): # caso tipo to=100
            #print c, "elemento tipo 1to1=x"
            # stili: roman highroman empty
            if re.match(r_1to1,c).group(3) in ["roman","highroman","empty"]:
                stili.append(c)
            else:
                da=int(re.match(r_1to1,c).group(1))
                finoa=int(re.match(r_1to1,c).group(2))+1
                for i in range(da,finoa):
                    paglist[i]=re.match(r_1to1,c).group(3)
            

        if re.match(r_eq1,c): # caso tipo 1=-
            #print c, "elemento tipo 1=-"
            da=int(re.match(r_eq1,c).group(1))
            paglist[da]=re.match(r_eq1,c).group(2)
            
        if re.match(r_eq,c): # caso tipo to=100
            #print c, "elemento tipo 2=1"
            da=int(re.match(r_eq,c).group(1))
            ini=int(re.match(r_eq,c).group(2))
            while da<np:
                paglist[da]=str(ini)
                da+=1
                ini+=1
                
                
    for stile in stili:
        da=int(re.match(r_1to1,stile).group(1))
        finoa=int(re.match(r_1to1,stile).group(2))+1
        stileCorr=re.match(r_1to1,stile).group(3)
        for i in range(da,finoa):
            if stileCorr=="roman":
                if paglist[i].isdigit():
                    paglist[i]=int_to_roman(int(paglist[i]))
            if stileCorr=="highroman":
                if paglist[i].isdigit():
                    paglist[i]=int_to_roman(int(paglist[i]),True)
    return paglist





###############
# funzioni varie di servizio
###############
def fileObj(nomeFile):
    pagina=wikipedia.Page(commons,nomeFile)
    paginaFile=wikipedia.FilePage(pagina)
    return paginaFile




def grab(url,output):
    page=opener.open(url+"?action=render")
    content=page.read()
    open(output,"wb").write(content)
    risposta="File salvato in "+output
    print risposta
    return

def commonsGrab(nomeFile):
    if not nomeFile.startswith("File:"):
        nomeFile="File:"+nomeFile
    #normalizzazione
    nomeFile=nomeFile.replace(" ","_")
    obj=fileObj(nomeFile)
    if os.path.isfile(nomeFile.replace("File:","")):
        print u"File già esistente"
    else:
        print "Download in corso..."
        grab(obj.fileUrl(),nomeFile.replace("File:",""))
        print "Finito"
    return

def simil(a,b,c=10):
    punti=0
    test=0
    if len(a)<=c or len(b)<=c:
        return -1
    for i in range(0,len(a)-c+1):
        test+=1
        #print a[i:i+c]
        if a[i:i+c] in b:
            punti+=1
    
    somiglianza=(punti*100/test)/100.
    return somiglianza

def find_stringa(stringa,idi,idf,dc=0,x=None,side="left"):
    if side=="right":
        idip=stringa.rfind(idi)
    else:
        idip=stringa.find(idi)
    idfp=stringa.find(idf,idip+len(idi))+len(idf)
    if idip>-1 and idfp>0:
        if x!=None:
            while stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
                if stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
                     idfp=stringa.find(idf,idfp)+len(idf)
                
        if dc==0:
            vvalore=stringa[idip+len(idi):idfp-len(idf)]
        else:
            vvalore=stringa[idip:idfp]
    else:
        vvalore=""
    return vvalore

def produci_lista(testo,idi,idf,dc=1,inizio=None):
    t=testo[:]
    lista=[]
    while not find_stringa(t,idi,idf,1,inizio)=="":
        el=find_stringa(t,idi,idf,1,inizio)
        t=t.replace(el,"",1)
        if dc==0:
            el=find_stringa(el,idi,idf,0,inizio)
        lista.append(el)
    return lista

numeral_map = tuple(zip(
    (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1),
    ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I')
))

def int_to_roman(i,highroman=False):
    result = []
    for integer, numeral in numeral_map:
        count = i // integer
        result.append(numeral * count)
        i -= integer * count
    roman=''.join(result)
    if not highroman:
        roman=roman.lower()
    return roman

def roman_to_int(n):
    n=n.upper()
    i = result = 0
    for integer, numeral in numeral_map:
        while n[i:i + len(numeral)] == numeral:
            result += integer
            i += len(numeral)
    return result

def isOdd(n):
    try:
        pari= (int(n)%2==0)
    except:
        pari= (roman_to_int(n) %2 ==0)
    return pari

# wiki template parser. Extracts the tl "template" from the containing "text"
# and returns a list containing a list (parameter list) and a dictionary (parameter names
# content)

# dependencies: code(), find_stringa(), produci_lista().
# The object can be reverted to a template code by rewrite().


def parseTemplate(testo,template):
    template=template[0:1].upper()+template[1:]
    testo=testo.replace("{{"+template,"{{"+template[0:1].upper()+template[1:])\
           .replace("{{"+template[0:1].lower()+template[1:],"{{"+template[0:1].upper()+template[1:])
           
    templateOld=find_stringa(testo,"{{"+template,"}}",1,"{{")
    template=templateOld[2:-2]
    t,b=code(template)
    t=t.split("|")
    
    n=0
    d={}
    l=[]
    
    
    for i in range(len(t)):
        x=t[i].split("=",1)
        x[0]=x[0].strip()
        if len(x)==2:
            x[1]=x[1].strip()
            d[x[0]]=x[1]
            l.append(x[0])
        else:
            d[str(n)]=x[0]
            
            l.append(str(n))
            n+=1

    for i in d:
        while find_stringa(d[i],"#e","#",1)!="":
            d[i]=d[i].replace(find_stringa(d[i],"#e","#",1),b[eval(find_stringa(d[i],"#e","#",0))])
    
    return d,l

def code(p=""):
    if p=="":

        p='''prova ''test'' <test1> prova' test {{test2<br />}} prova test
<test1> prova test [[test3' {{test2' <br />}} ]]
prova [test4] prova' http://www.alex'.com prova '''
    lista=[]
    p1=p[:]
    ne=0
    l=produci_lista(p1,u"<!--",u"-->",1)
    for r in l:
        el="#e"+str(ne)+"#"
        lista.append(r)
        p1=p1.replace(r,el)
        ne=ne+1
        
    l=produci_lista(p1,"{{","}}",1,inizio="{{")
    for r in l:
        el="#e"+str(ne)+"#"
        lista.append(r)
        p1=p1.replace(r,el)
        ne=ne+1
    #print l
    #return
    l=produci_lista(p1,u"<",u">",1)
    for r in l:
        el="#e"+str(ne)+"#"
        lista.append(r)
        p1=p1.replace(r,el)
        ne=ne+1
    l=produci_lista(p1,u"[[",u"]]",1)
    for r in l:
        el="#e"+str(ne)+"#"
        lista.append(r)
        p1=p1.replace(r,el)
        ne=ne+1
            
    l=produci_lista(p1,u"[",u"]",1)
    for r in l:
        el="#e"+str(ne)+"#"
        lista.append(r)
        p1=p1.replace(r,el)
        ne=ne+1
    
    return [p1,lista]

# d: dictionary from parseTemplate: l: list from parseTemplate
def rewrite(oggettoTemplate):
    d=oggettoTemplate[0]
    l=oggettoTemplate[1]
    testo="{{"+d["0"]+"\n"
    for i in l[1:]:
        if (i.isdigit()):
            testo+=" | "+d[i]+"\n"
        else:
            testo+=" | "+i+" = "+d[i]+"\n"
    testo+="}}\n"
    return testo



def rel_atob(a,b):
    # creazione di link relativo da A a B
    path=os.path.relpath(b,a).replace("\\","/")
    return path+"/" if path.endswith("..") else path

def split(pagina):
    splitSourcePage=wikipedia.Page(sito,pagina)
    testo=splitSourcePage.get().split("\n")
    lista=produci_lista(testo,"==[[Pagina","]]==")
    print "Pagine: "+len(lista)
    pointer=testo.find(lista[0])
    iniziotesto=testo[0:pointer]
    testo=testo[pointer:]
    return
    
    
    



def main(argv):
    #print argv
    #def carica(fileDjvu,ini=None,fin=None,sovrascrivi=False,\
    #      aggiustaParagrafi=False,test=False,soloNs0=False,piu_uno=True):
    fileDjvu=argv[0]
    sovrascrivi=False
    aggiustaParagrafi=False
    test=False
    
    ini=None
    fin=None
    soloNs0=False
    piu_uno=True
    for arg in argv[1:]:
        if arg.startswith("sovrascrivi="):
            sovrascrivi=(arg.replace("sovrascrivi=","")=="True")
        if arg.startswith("aggiustaParagrafi="):
            aggiustaParagrafi=(arg.replace("aggiustaParagrafi=","")=="True")
        if arg.startswith("ini="):
            ini=int(arg.replace("ini=",""))
        if arg.startswith("fin="):
            fin=int(arg.replace("fin=",""))
        if arg.startswith("soloNs0="):
            soloNs0=(arg.replace("soloNs0=","")=="True")
        if arg.startswith("piu_uno="):
            piu_uno=(arg.replace("piu_uno=","")=="True")
        if arg.startswith("test="):
            test=(arg.replace("test=","")=="True")
            
    print "Comando: carica(", fileDjvu,ini,fin,sovrascrivi,aggiustaParagrafi,test,soloNs0,piu_uno,")"
    carica(fileDjvu,ini,fin,sovrascrivi,aggiustaParagrafi,test,soloNs0,piu_uno)
   
    return

if __name__=="__main__":
    main(sys.argv[1:])