From b9a41bb8bb01c8aa961db19bd1b080305bf7348f Mon Sep 17 00:00:00 2001 From: Cyrille LOUARN Date: Thu, 26 Oct 2023 18:59:56 +0200 Subject: [PATCH] [1.9.27] - See changelog --- CHANGELOG.md | 9 + README.md | 106 +++++ src/usr/bin/tyto | 2 +- .../program/__pycache__/check.cpython-311.pyc | Bin 39105 -> 40659 bytes .../program/__pycache__/post.cpython-311.pyc | Bin 9901 -> 10842 bytes .../program/__pycache__/wip.cpython-311.pyc | Bin 9032 -> 9194 bytes src/var/lib/tyto/program/check.py | 382 +++++++++++------- src/var/lib/tyto/program/post.py | 48 ++- src/var/lib/tyto/program/wip.py | 5 +- 9 files changed, 400 insertions(+), 152 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 243d2c1..063596b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,15 @@ Tyto - Littérateur # CURRENTLY IN DEV ! +## [1.9.27] +- fix when target article .tyto is missing +- Nearly all stats are added in DB from modules +- Only used tags and stats (or nearly) are added to DB +- cleaner code +- check: +- - added words_tags (strong, italics...) +- - "all" target now ready + ## [1.9.26] - user can indent titles in text - prepared words markers (strong, bolds) (some to add soon) diff --git a/README.md b/README.md index f4a0d0e..188c5db 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,109 @@ tyto - stats for article words - Translate logs in english ! +## Exemple d'article +``` + Pour ne pas inclure cet article dans les sitemaps : +! NoSitemap + +title: tests d'un article +about: À propos de cet article de test +tags: hello, my big world,here +author: echolib +date: 2023-09-30 +logo: /testimg/hi.png + +link: Lien à reprendre + https:// + Text alternatif + +link: Réservez ici + https:// + Billets + +file: voir l'image + PNGs/hi.png + Un png ! + +image: MyCar + PNGs/hi.png + Un png ! + +file: télécharger ce fichier + @PDFs/hello.pdf + Un PDF ! + +abbr: css + Cascading StyleSheet + CSS + +abbr: HTML + Hyper Text Markup Langage + HTML + +code: test + @RAWS/test.py + Du code à afficher en HTML + +----- +# La ligne suivante est un commentaire HTML "" +;; Commentaire +-> top +#1 Titre en h2 +(( + ;; HTML comment + # Show logo set in header, using '_image:logo' + _image:logo tyto_logo w=120 +)) + +-> newtitle + #2 Titre en h3 décalé dans le texte + (( + Parce que c'est *_bien_* comme /_présentation_/ *_erreur + ou pas, si fermé_* + /_ ;_echolib_; _/ + )) + + +(( +Il /_faut_/ ce __Lien à reprendre et __Réservez ici et --télécharger ce fichier +ou encore faire une ::css pour du ::HTML. __Réservez ici et --voir l'image + + icode 1 : {_hello(_world_)_}, icode 2 : {_print("")_} + icode 3 : {_{__}_}, icode 4 : {_echo "Hello"_} +)) + +(( + _image:MyCar + <: mylist + + Item 1 + ++ Sub-Item 1 + +++ Sub-Sub-item 1 + ==== >_top: Go to Top_< + ==== >_top: Another anchor_< + :> +)) + +_code:test +{{ + # Du code brut pour Tyto + {{ + Un exemple de code + }} +}} + +[[ + [" + ;; A great quote here ! + cite: Someone + date: 2023-10-13 + book: A History + lang: EN + link: https://... + + (( + Here, i am + )) + "] +]] +``` diff --git a/src/usr/bin/tyto b/src/usr/bin/tyto index 595eb11..797857c 100755 --- a/src/usr/bin/tyto +++ b/src/usr/bin/tyto @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Version: 1.9.26 +# Version: 1.9.27 # Updated: 2023-10-18 1697613100 # Tyto - Littérateur diff --git a/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc index 8670f26608bf101fb0a46dddd3de2659164fabc6..a374e7b8975c072826c472da0f4ab6e1a4af968f 100644 GIT binary patch literal 40659 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 diff --git a/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc index 399db3f05aa1d36057b5398754adba52beee57d2..653ea4908d0901a9fc3b643286034ee39260f084 100644 GIT binary patch delta 2634 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 diff --git a/src/var/lib/tyto/program/__pycache__/wip.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/wip.cpython-311.pyc index e9381e49ab058b11acbcad562546ba2880ae8691..0d13eaa9547cd8f54677af78af641f471ae93c27 100644 GIT binary patch delta 843 zcmZuvO=uHA6yC`un{<;+j7h8}O*e@FyB=CAJ!vWy<6i>>O%4W?WzDW_LVnhnEgq~l z5m6CjE`lI>si=4;Q9OGP>di_{d(ewP^dxxe$$68e?ZF50@qXt0eDh}g%|_ zOzL-!Su^>^;ajqwSt2`s7wF~a#kKwmG~N8n|GEx4p64aV))MIR?S-3OEW71OS#e3=pAXq5W~-iT5&aeLPEx z<57Ap^dWcv0!e@rm6dcN4XQSTGE>MWk=kOSdqFuO1#=LQ01ncJv8gor2~VRnPSkI8JclWhYV zi`cN22wr6VDf%e;uBtLkllh_sd*nqYm>0v387v0gg7e|i^6XavhE&dEGf-%C%;lza e0@s-jD3VqBG&j2^g%W>+Z73r8Gk4VsdH(>Ozp*(0 delta 687 zcmZuv&ubG=5Z>3#Zqwat(vpphZsP{i78Wa^H-)x%5Iqz`@sxwaHCb#RY1VlO9@>NS z){7wX7kCg6MUWLddDoLiVWEPchk8;}kV3(km;O4q@IGd~dGltznf-q4{nh+4$FVf} zUT)Q+zqQBt4cjD7r}OK#!2PM4ufIJJR3g;ObVJ)q`?Y971>x!gx(W zi}(espL^5r$OU{|BRW@GO)b)vd~Yt^ubiC41SWUcWu;Mk^2z#}egJ VT&gV>%A)i`JAxJ5uHDXX+CS2VjaC2v diff --git a/src/var/lib/tyto/program/check.py b/src/var/lib/tyto/program/check.py index 39bb82f..7f30735 100644 --- a/src/var/lib/tyto/program/check.py +++ b/src/var/lib/tyto/program/check.py @@ -58,7 +58,7 @@ def ready(): def manage(action, target): # target is "all" if args.targets: - multiple_targets + multiple_targets() return # target is not "all" @@ -71,7 +71,9 @@ def manage(action, target): # Also used with multiple (loop) # #--------------------------------# def is_article(target): - valid(target) or tools.exit(targets, post.error) + if not valid(target): + if targets: return + else: sys.exit(post.error) # When all is OK # Will create post database, but now, show some values @@ -83,7 +85,7 @@ def is_article(target): print() """ # Write to post database - cf_update_values() + cf_update_values("after") #===========================================# @@ -95,7 +97,9 @@ def valid(target): targets = args.targets # Target is a tyto article format - post.is_article(target) or tools.exit(targets, post.error) + if not post.is_article(target): + return False + if not post.do_chk: post.error = debug.out(210, post.chk_date, post.uri, True, 0, False) return False @@ -104,6 +108,9 @@ def valid(target): tools.create_file(post.cf_uri, post.ini_template) post.cf_load() + # Add statistics to post database + cf_update_values("before") + global css css = domain.css @@ -141,6 +148,10 @@ def valid(target): post.error == 0 and anchors_links() \ or tools.exit(targets, post.error) + # Words Tags (Strong, bold...) + post.error == 0 and words_tags() \ + or tools.exit(targets, post.error) + # Quotes post.error == 0 and sl_ptags(post.ptags[1]) \ or tools.exit(targets, post.error) @@ -165,6 +176,7 @@ def valid(target): #-------------------------------------------# def multiple_targets(): ready() + post.find_tyto_article() #=====================# @@ -174,16 +186,22 @@ def multiple_targets(): # One Line needed tags # #----------------------# def ol_tags(): - global sitemap, src_uri + global sitemap, src_uri, stats_tyto_head_coms + global stats_total_files + stats_total_files = 0 sitemap = "True" + stats_tyto_head_coms = 0 for ln, line in enumerate(headers, 1): # Optional one line markers if line.startswith("#"): - post.stats_tyto_head_coms += 1 + stats_tyto_head_coms += 1 + post.cf_set("STATS_HEADERS", "tyto_coms", str(stats_tyto_head_coms)) + elif line.startswith(post.nositemap): - sitemap = "False" + post.cf_set("HEADERS", "sitemap", "False") + elif line.startswith(post.logo[0]): if not post.logo[1]: post.logo = (post.logo[0], ol_tag_value(line, False)) @@ -197,30 +215,37 @@ def ol_tags(): # =========================== elif not post.title[1] and line.startswith(post.title[0]): post.title = (post.title[0], ol_tag_value(line, False)) + if not is_ol_tag(post.title[0], post.title[1]): + return False + post.cf_set("HEADERS", "title", post.title[1]) elif not post.about[1] and line.startswith(post.about[0]): post.about = (post.about[0], ol_tag_value(line, False)) + if not is_ol_tag(post.about[0], post.about[1]): + return False + post.cf_set("HEADERS", "about", post.about[1]) elif not post.date[1] and line.startswith(post.date[0]): post.date = (post.date[0], ol_tag_value(line, False)) + if not is_ol_tag(post.date[0], post.date[1]): + return False + elif not is_valid_date(post.date[1]): + return False + post.date = ("date:", tools.local_date(post.date[1])) + post.cf_set("HEADERS", "date", post.date[1]) elif not post.author[1] and line.startswith(post.author[0]): post.author = (post.author[0], ol_tag_value(line, True)) + if not is_ol_tag(post.author[0], post.author[1]): + return False + post.cf_set("HEADERS", "authors", post.author[1]) elif not post.tags[1] and line.startswith(post.tags[0]): post.tags = (post.tags[0], ol_tag_value(line, True)) + if not is_ol_tag(post.tags[0], post.tags[1]): + return False + post.cf_set("HEADERS", "tags", post.tags[1]) - - # Sets are done from loop - # Check if tag value exists - # ========================= - if not is_ol_tag(post.date[0], post.date[1]): return False - if not is_valid_date(post.date[1]): return False - if not is_ol_tag(post.title[0], post.title[1]): return False - if not is_ol_tag(post.about[0], post.about[1]): return False - if not is_ol_tag(post.author[0], post.author[1]): return False - if not is_ol_tag(post.tags[0], post.tags[1]): return False - # Default domain logo for this post if not post.logo[1]: src_uri = "%stemplate/%s"%(domain.www_url, domain.logo) @@ -273,6 +298,7 @@ def is_valid_date(date): try: parse(date) chk_date = tools.nowdate() + post.cf_set("CHECK", "date", chk_date) return True except: post.error = debug.out(50, "%s"%date, post.uri, True, 2, False) @@ -293,13 +319,19 @@ def ml_tags(): continue if line.startswith(post.ml_tags): - tag = line.rsplit(":")[0] + ":" + tag_name = line.rsplit(":")[0] + tag = tag_name + ":" + post.ml_tags_stats[tag] = post.ml_tags_stats[tag] + 1 if not ml_tag_values(ln, tag, post.ml_tags_stats[tag]): return False c = 2 + post.cf_set("STATS_HEADERS", + "%ss"%tag_name, + str(post.ml_tags_stats[tag]) + ) continue return True @@ -375,6 +407,7 @@ def ml_tag_values(ln, tag, stats): if tag == post.ml_tags[0]: section = "LINKS" post.stats_text_links += post.text_contents.count(tyto_value) + post.cf_set("STATS_TEXTS", "links", str(post.stats_text_links)) html_value = tyto.a_link%( value2, "%s link"%css, "%%s", value3, value1 ) @@ -383,6 +416,7 @@ def ml_tag_values(ln, tag, stats): elif tag == post.ml_tags[2]: section = "FILES" post.stats_text_files += post.text_contents.count(tyto_value) + post.cf_set("STATS_TEXTS", "files", str(post.stats_text_files)) html_value = tyto.a_link%( value2, "%s file"%css, "%%s", value3, value1 ) @@ -391,6 +425,7 @@ def ml_tag_values(ln, tag, stats): elif tag == post.ml_tags[1]: section = "IMAGES" post.stats_text_images += post.text_contents.count(tyto_value) + post.cf_set("STATS_TEXTS", "images", str(post.stats_text_images)) html_value = tyto.image_link%( value2, "%%s image", "%%s", value3, value3, "%%s" @@ -400,6 +435,7 @@ def ml_tag_values(ln, tag, stats): elif tag == post.ml_tags[3]: section = "RAWS" post.stats_text_raws += post.text_contents.count(tyto_value) + post.cf_set("STATS_TEXTS", "raws", str(post.stats_text_raws)) html_value = ""%value3 with open(value2_uri, "r") as f: html_value = "%s\n%s"%(html_value, f.read()) @@ -410,6 +446,7 @@ def ml_tag_values(ln, tag, stats): elif tag == post.ml_tags[4]: section = "CODES" post.stats_text_codes += post.text_contents.count(tyto_value) + post.cf_set("STATS_TEXTS", "codes", str(post.stats_text_codes)) htmlbcode = ""%value3 with open(value2_uri, "r") as f: for ln, line in enumerate(f.read().rsplit("\n"), 1): @@ -424,10 +461,12 @@ def ml_tag_values(ln, tag, stats): elif tag == post.ml_tags[5]: section = "ABBRS" post.stats_text_abbrs += post.text_contents.count(tyto_value) + post.cf_set("STATS_TEXTS", "abbrs", str(post.stats_text_abbrs)) html_value = '%s'%( css, value2, value3 ) - + + # Set in post database, source and HTML content post.cf_set(section, "%s_%s"%(tag.replace(":", ""), stats), tyto_value) post.cf_set(section, "html_%s"%stats, html_value) @@ -442,7 +481,7 @@ def ml_tag_values(ln, tag, stats): # - ... for post directory # #--------------------------------# def is_value2_file_exists(ln, tag, val2): - global value2, src_uri, value2_uri + global value2, src_uri, value2_uri, stats_total_files # uri "@..." means generic folders if val2[0].startswith("@"): @@ -477,8 +516,9 @@ def is_value2_file_exists(ln, tag, val2): return False # Add file to [SOURCE_FILES] post database - post.stats_total_files += 1 - post.cf_set("SOURCE_FILES", "file_%s"%post.stats_total_files, src_uri) + stats_total_files += 1 + post.cf_set("SOURCE_FILES", "file_%s"%stats_total_files, src_uri) + post.cf_set("STATS_FILE", "files", str(stats_total_files)) return True @@ -548,6 +588,10 @@ def sl_ptags(markers): index0 = index1 = -1 tag_ln = "" post.ptags_stats[markers[2]] += 1 + post.cf_set("STATS_TEXTS", + markers[2], + str(post.ptags_stats[markers[2]]) + ) # paragraphs don't need html wip yet if markers[2] in ("parags", "divs"): @@ -594,7 +638,6 @@ def sl_ptags(markers): ), post.uri, True,2, False) return False - print(": stats", markers[2], post.ptags_stats[markers[2]]) return True @@ -609,6 +652,7 @@ def sl_ptags(markers): def icodes(): global texts + stats_text_icodes = 0 markers = post.words_markers for ln, line in enumerate(texts, post.head_lines + 1): @@ -652,7 +696,7 @@ def icodes(): icodes = re.findall('%s(.*?)%s'%(markers[0][4], markers[0][5]), line) for icode in icodes: - post.stats_text_icodes += 1 + stats_text_icodes += 1 icnew = markers[0][4] + icode + markers[0][5] line = line.replace(icnew, "") @@ -660,12 +704,12 @@ def icodes(): html_val = icnew.replace(markers[0][4], markers[0][2]%css) post.cf_set( "ICODES", - "icode_%s"%post.stats_text_icodes, + "icode_%s"%stats_text_icodes, markers[0][0] + icode + markers[0][1] ) post.cf_set( "ICODES", - "html_%s"%post.stats_text_icodes, + "html_%s"%stats_text_icodes, html_val.replace(markers[0][5], markers[0][3]) ) @@ -675,7 +719,7 @@ def icodes(): icodes = re.findall('%s(.*?)%s'%(markers[1][4], markers[1][5]), line) for icode in icodes: - post.stats_text_icodes += 1 + stats_text_icodes += 1 icnew = markers[1][4] + icode + markers[1][5] line = line.replace(icnew, "") @@ -683,17 +727,19 @@ def icodes(): html_val = icnew.replace(markers[1][4], markers[1][2]%css) post.cf_set( "ICODES", - "icode_%s"%post.stats_text_icodes, + "icode_%s"%stats_text_icodes, markers[1][0] + icode + markers[1][1] ) post.cf_set( "ICODES", - "html_%s"%post.stats_text_icodes, + "html_%s"%stats_text_icodes, html_val.replace(markers[1][5], markers[1][3]) ) texts[ln - 1 - post.head_lines] = line - + + post.cf_set("STATS_TEXTS", "icodes", str(stats_text_icodes)) + return True @@ -705,10 +751,14 @@ def icodes(): # Return True/False # #----------------------------# def sl_stags(): - global anchors_ids - anchors_ids = () # Uniq anchors IDs - - for ln, line in enumerate(texts, post.head_lines + 1): + global anchors_ids, stats_tyto_text_coms + + anchors_ids = () # Uniq anchors IDs + stats_tyto_text_coms = stats_html_coms = 0 + stats_text_anc_ids = 0 + stats_titles = 0 + + for ln, line in enumerate(texts, post.head_lines + 1): linels = line.lstrip() # legacy Tyto Titles @@ -724,40 +774,43 @@ def sl_stags(): debug.out(52, "%s) %s..."%(ln, linels[0:10]), post.uri, True, 1, False) return False - post.stats_titles += 1 + stats_titles += 1 + post.cf_set("STATS_TEXTS", "titles", str(stats_titles)) # Create html value for this title in database post.cf_set( "TITLES", - "title_%s"%post.stats_titles, + "title_%s"%stats_titles, line ) post.cf_set( "TITLES", - "html_%s"%post.stats_titles, + "html_%s"%stats_titles, post.html_titles[linels[0:2]]%(css, line[3:]) ) - - + # Count Tyto Comments elif line.lstrip().startswith("#"): - post.stats_tyto_text_coms += 1 - - + stats_tyto_text_coms += 1 + post.cf_set("STATS_TEXTS", "tyto_coms", str(stats_tyto_text_coms)) + + # Count HTML comments elif line.lstrip().startswith(post.text_comments): - post.stats_html_coms += 1 + stats_html_coms += 1 + post.cf_set("STATS_TEXTS", "html_coms", str(stats_html_coms)) + # Convert tyto commented marker to HTML if line.lstrip().startswith(post.text_comments[0]): real_com = line.lstrip()[3:] post.cf_set( "COMMENTS", - "comm_%s"%post.stats_html_coms, + "comm_%s"%stats_html_coms, line.lstrip() ) post.cf_set( "COMMENTS", - "html_%s"%post.stats_html_coms, + "html_%s"%stats_html_coms, ''%real_com ) @@ -778,20 +831,21 @@ def sl_stags(): post.title[1], post.title[1], "%%s" ) ) - + # Anchor source elif line.lstrip().startswith(post.anchor_target[0]): - anchor_id = tools.get_css(line, post.anchor_target[0]) + anchor_id = tools.get_css(line, post.anchor_target[0]) if anchor_id in anchors_ids: post_error = \ debug.out(54, '%s) "%s"'%(ln, anchor_id), post.uri, True, 2, False) return False anchors_ids = (*anchors_ids, anchor_id) - post.stats_text_anc_ids += 1 - - return True + stats_text_anc_ids += 1 + post.cf_set("STATS_TEXTS", "anc_targets", str(stats_text_anc_ids)) + + return True #===========================# @@ -800,6 +854,8 @@ def sl_stags(): #---------------------------# def anchors_links(): markers = post.anchor_link + stats_text_anc_links = 0 + for ln, line in enumerate(texts, post.head_lines + 1): anc_links = re.findall('%s(.*?)%s'%(markers[0], markers[1]), line) if not anc_links: @@ -823,13 +879,13 @@ def anchors_links(): return False # Set to post Database - post.stats_text_anc_links += 1 + stats_text_anc_links += 1 post.cf_set("ANCHORS", - "anchor_%s"%post.stats_text_anc_links, + "anchor_%s"%stats_text_anc_links, post.anchor_set[0]%anc_link ) post.cf_set("ANCHORS", - "html_%s"%post.stats_text_anc_links, + "html_%s"%stats_text_anc_links, post.anchor_set[1]%(css, anc_id, anc_title) ) else: @@ -837,104 +893,158 @@ def anchors_links(): debug.out(51, '%s) "-> %s"'%(ln, anc_id), post.uri, True, 2, False) return False + post.cf_set("STATS_TEXTS", "anc_links", str(stats_text_anc_links)) return True +#======================================# +# Count and return sub indices in text # +#--------------------------------------# +def find_sub_indices(full, sub): + return [index for index in range(len(full)) if full.startswith(sub, index)] + +#================================================# +# From position of sub tag: return article line # +# When error, to let user know real line article # +# char is indice tag position # +#------------------------------------------------# +def find_line_sub(char): + for fc, lc, ln in lines_chars: + if fc <= char and char <= lc: + return ln + #======================================= -# CHeck paired words marks # -# Count for stats # +# CHeck paired words tagss # +# Count for tags stats + words # # ! No neeed to create HTML in post db # #--------------------------------------# def words_tags(): - print("words_tags: soon...") + global lines_chars + + # Create List lines number and number of characters in line + # (In error case, show line number) + old_len = 0 # len(line) + lines_chars = (()) + stats_text_chars = 0 + for ln, line in enumerate(texts, post.head_lines + 1): + stats_text_chars = stats_text_chars + len(line) + lines_chars = lines_chars + ((old_len, stats_text_chars, ln),) + old_len = stats_text_chars + + post.cf_set("STATS_TEXTS", "chars", str(stats_text_chars)) + + # Create article in block text format + # Also count words written + block_texts = '' + for line in texts: + block_texts = block_texts + line + + post.cf_set("STATS_TEXTS", + "words", + str(sum(1 for w in block_texts.split())) + ) + + # For each word tag, get position indicies + for i, tags in enumerate(post.words_tags): + indices_o = find_sub_indices(block_texts, tags[0]) + indices_c = find_sub_indices(block_texts, tags[1]) + if not indices_o and not indices_c: + continue + + # Count and compare opened and closes tags numbers + len_o = len(indices_o) + len_c = len(indices_c) + + # Not paired tags + if len_o != len_c: + post.error = \ + debug.out(53, "%s %s, %s %s"%( + len_o, tags[0], + len_c, tags[1] + ), post.uri, True, 2, False) + return False + + # Test if tags are opened > closed + for n in range(len_o): + # Current opened must be smaller than current closed + if indices_o[n] > indices_c[n]: + post.error = \ + debug.out(53, '%s) "%s...%s"'%( + find_line_sub(indices_o[n]), tags[1], tags[0] + ), post.uri, True, 2, False) + return False + + # Other mismatches opens/closed tags + else: + # Current closed must be higher than opened + 1 + try: + if indices_c[n] > indices_o[n+1]: + post.error = \ + debug.out(53, '%s) "%s...%s"'%( + find_line_sub(indices_c[n]), tags[0], tags[0] + ), post.uri, True, 2, False) + return False + except: + continue + + # Add tag statistic to post database + post.cf_set("STATS_TEXTS", tags[2], str(len_o)) + + return True +#==================================# +# Update post configuration file # +# part: # +# before > first generic datas # +# after > after all check modules # +#----------------------------------# +def cf_update_values(part): + # Generic known first datas, before check modules + if part == "before": + post.cf_set("DOMAIN", "name", domain.name) + post.cf_set("CHECK", "static", str(domain.static)) + post.cf_set("CHECK", "hash", post.wrk_id) -#================================# -# Update post configuration file # -#--------------------------------# -def cf_update_values(): - post.date = ("date:", tools.local_date(post.date[1])) - - post.cf_set("DOMAIN", "name", domain.name) - - # [FILE] - post.cf_set("FILE", "id", post.uri_id) - post.cf_set("FILE", "uri", post.uri) - post.cf_set("FILE", "db", post.cf_uri) - post.cf_set("FILE", "target", post.wrk_target) - - # [HEADERS] - # --------- - post.cf_set("HEADERS", "title", post.title[1]) - post.cf_set("HEADERS", "about", post.about[1]) - post.cf_set("HEADERS", "date", post.date[1]) - post.cf_set("HEADERS", "tags", post.tags[1]) - post.cf_set("HEADERS", "authors", post.author[1]) - post.cf_set("HEADERS", "sitemap", str(sitemap)) - - # [check] + # [FILE] + post.cf_set("FILE", "id", post.uri_id) + post.cf_set("FILE", "uri", post.uri) + post.cf_set("FILE", "db", post.cf_uri) + post.cf_set("FILE", "target", post.wrk_target) + + # [WIP] + # ----- + post.cf_set("WIP", "hash", post.wip_hash) + post.cf_set("WIP", "date", post.wip_date) + post.cf_set("WIP", "web", "%s%s"%(domain.wip_url, post.wrk_target)) + post.cf_set("WIP", "uri", "%s%s"%(domain.wip, post.wrk_target)) + + # [WWW] + # ----- + post.cf_set("WWW", "hash", post.www_hash) + post.cf_set("WWW", "date", post.www_date) + post.cf_set("WWW", "web", "%s%s"%(domain.www_url, post.wrk_target)) + post.cf_set("WWW", "uri", "%s%s"%(domain.www, post.wrk_target)) + + # Stats (these, cause i want them first) + post.cf_set("STATS_FILE", "lines", str(post.lines)) + post.cf_set("STATS_HEADERS", "lines", str(post.head_lines)) + post.cf_set("STATS_TEXTS", "lines", str(post.text_lines)) + + return + + # Datas after check modules + # ------------------------- + # [CHECK] # ------- - post.cf_set("CHECK", "hash", post.wrk_id) - post.cf_set("CHECK", "date", chk_date) - post.cf_set("CHECK", "static", str(domain.static)) post.cf_set("CHECK", "errors", "False") - # [WIP] - # ----- - post.cf_set("WIP", "hash", post.wip_hash) - post.cf_set("WIP", "date", post.wip_date) - post.cf_set("WIP", "web", "%s%s"%(domain.wip_url, post.wrk_target)) - post.cf_set("WIP", "uri", "%s%s"%(domain.wip, post.wrk_target)) - - # [WWW] - # ----- - post.cf_set("WWW", "hash", post.www_hash) - post.cf_set("WWW", "date", post.www_date) - post.cf_set("WWW", "web", "%s%s"%(domain.www_url, post.wrk_target)) - post.cf_set("WWW", "uri", "%s%s"%(domain.www, post.wrk_target)) - # [STATS_FILE] # ------------ - stats_tyto_all_coms = post.stats_tyto_text_coms + post.stats_tyto_head_coms - post.cf_set("STATS_FILE", "lines", str(post.lines)) + stats_tyto_all_coms = stats_tyto_text_coms + stats_tyto_head_coms + stats_tyto_all_coms > 0 and \ post.cf_set("STATS_FILE", "tyto_coms", str(stats_tyto_all_coms)) - post.cf_set("STATS_FILE", "files", str(post.stats_total_files)) - - # [STATS_HEADERS] - # --------------- - post.cf_set("STATS_HEADERS", "lines", str(post.head_lines)) - post.cf_set("STATS_HEADERS", "tyto_coms", str(post.stats_tyto_head_coms)) - post.cf_set("STATS_HEADERS", "links", str(post.ml_tags_stats["link:"])) - post.cf_set("STATS_HEADERS", "files", str(post.ml_tags_stats["file:"])) - post.cf_set("STATS_HEADERS", "images", str(post.ml_tags_stats["image:"])) - post.cf_set("STATS_HEADERS", "abbrs", str(post.ml_tags_stats["abbr:"])) - post.cf_set("STATS_HEADERS", "codes", str(post.ml_tags_stats["code:"])) - post.cf_set("STATS_HEADERS", "raws", str(post.ml_tags_stats["raw:"])) - - # [STATS_TEXTS] - # ------------- - post.cf_set("STATS_TEXTS", "lines", str(post.text_lines)) - post.cf_set("STATS_TEXTS", "tyto_coms", str(post.stats_tyto_text_coms)) - post.cf_set("STATS_TEXTS", "html_coms", str(post.stats_html_coms)) - post.cf_set("STATS_TEXTS", "anc_targets", str(post.stats_text_anc_ids)) - post.cf_set("STATS_TEXTS", "anc_links", str(post.stats_text_anc_links)) - post.cf_set("STATS_TEXTS", "titles", str(post.stats_titles)) - post.cf_set("STATS_TEXTS", "parags", str(post.ptags_stats["parags"])) - post.cf_set("STATS_TEXTS", "divs", str(post.ptags_stats["divs"])) - post.cf_set("STATS_TEXTS", "bcodes", str(post.ptags_stats["bcodes"])) - post.cf_set("STATS_TEXTS", "bcodes_lines", str(post.stats_bcodes_lines)) - post.cf_set("STATS_TEXTS", "quotes", str(post.ptags_stats["quotes"])) - post.cf_set("STATS_TEXTS", "lists", str(post.ptags_stats["lists"])) - # Founds from header tags - post.cf_set("STATS_TEXTS", "links", str(post.stats_text_links)) - post.cf_set("STATS_TEXTS", "files", str(post.stats_text_files)) - post.cf_set("STATS_TEXTS", "images", str(post.stats_text_images)) - post.cf_set("STATS_TEXTS", "abbrs", str(post.stats_text_abbrs)) - post.cf_set("STATS_TEXTS", "icodes", str(post.stats_text_icodes)) - post.cf_set("STATS_TEXTS", "codes", str(post.stats_text_codes)) - post.cf_set("STATS_TEXTS", "raws", str(post.stats_text_raws)) - + # ============================ # Write new values in database # ============================ diff --git a/src/var/lib/tyto/program/post.py b/src/var/lib/tyto/program/post.py index 3b05878..6f1fe6d 100644 --- a/src/var/lib/tyto/program/post.py +++ b/src/var/lib/tyto/program/post.py @@ -33,7 +33,7 @@ #-------------------------- import os, sys, configparser -import args, domain, debug, tools, tyto +import args, domain, debug, tools, tyto, check error = 0 @@ -47,6 +47,8 @@ write = False # When updating database in cf_set(), cf_write() # load database # #--------------------------------------------# def is_article(target): + global error + # User MUST be in articles/ domain.user_dir.startswith(domain.wrk_articles) or \ debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True) @@ -58,7 +60,9 @@ def is_article(target): # Article exists global uri - uri = os.path.join(domain.user_dir, target) + if args.targets: cur_dir = domain.wrk_articles + else: cur_dir = domain.user_dir + uri = os.path.join(cur_dir, target) if not os.path.exists(uri): error = debug.out(5, "False", uri, True, 2, False) return False @@ -82,6 +86,7 @@ def is_article(target): cf_load() cf_datas() compare_datas() + return True @@ -239,21 +244,40 @@ def cf_write(): write = False +#====================================================# +# Search and return .tyto file in domain root folder # +#----------------------------------------------------# +def find_tyto_article(): + nothere = (domain.wrk_files, domain.wrk_images) + os.chdir(domain.wrk_articles) + + for root,dirs,files in os.walk(domain.wrk_articles): + if root.startswith(nothere): + continue + + for f in files: + if f.endswith(".tyto"): + f_uri = os.path.join(root, f) + target = f_uri.rsplit(domain.wrk_articles)[1] + + args.action == "check" and check.is_article(target) + + + + #======# # MAIN #======================================================================= #======# # Statistics # ========== -stats_tyto_head_coms = 0 -stats_tyto_text_coms = 0 -stats_html_coms = 0 -stats_titles = 0 -stats_bcodes = 0 stats_bcodes_lines = 0 + +stats_bcodes = 0 stats_quotes = 0 stats_parags = 0 stats_lists = 0 stats_divs = 0 + stats_links = 0 stats_images = 0 stats_files = 0 @@ -261,17 +285,12 @@ stats_raws = 0 stats_codes = 0 stats_abbrs = 0 -stats_total_files = 0 - -stats_text_anc_ids = 0 -stats_text_anc_links = 0 stats_text_links = 0 stats_text_files = 0 stats_text_images = 0 stats_text_abbrs = 0 stats_text_codes = 0 stats_text_raws = 0 -stats_text_icodes = 0 # head_contents @@ -288,7 +307,7 @@ about = ("about:", False) date = ("date:", False) tags = ("tags:", False) author = ("author:", False) -logo = ("logo:", False) # optional +logo = ("logo:", False) # optional # Multiple lines (3) markers ml_tags = ("link:", "image:", "file:", "raw:", "code:", "abbr:") @@ -310,7 +329,7 @@ ml_tags_stats = { } # Markers with uri in value2 -value2s_uri = (ml_tags[1], ml_tags[2], ml_tags[3], ml_tags[4]) +value2s_uri = (ml_tags[1], ml_tags[2], ml_tags[3], ml_tags[4]) value2s_ext_uris = ("http", "ftp") # text_contents @@ -359,6 +378,7 @@ words_tags = ( ("~_", "_~", "dels", '', ''), ("._", "_.", "underlines", '', ''), ("/_", "_/", "emphasis", '', ''), + (";_", "_;", "italics", '', ''), ) # Specifics convertion diff --git a/src/var/lib/tyto/program/wip.py b/src/var/lib/tyto/program/wip.py index 2fc0b98..a3bb5e5 100644 --- a/src/var/lib/tyto/program/wip.py +++ b/src/var/lib/tyto/program/wip.py @@ -49,6 +49,7 @@ import tyto, tools, post, domain def bcode(lines): lines = lines.rsplit("\n") html_bcode = "" + for ln, line in enumerate(lines): if ln == 0: # Opened marker css = tools.get_css(line, post.ptags[0][0]) @@ -69,7 +70,9 @@ def bcode(lines): else: html_bcode = "%s\n%s"%(html_bcode, line) html_bcode = tyto.code_bcode%(css, html_bcode) - #print(html_bcode) + + post.cf_set("STATS_TEXTS", "bcodes_lines", str(post.stats_bcodes_lines)) + return html_bcode