Пример #1
0
def main():

    logging.basicConfig(
        #filename=LOGDIR + "/rssSocial.log",
        stream=sys.stdout,
        level=logging.INFO,
        format="%(asctime)s [%(filename).12s] %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    msgLog = "Launched at %s" % time.asctime()
    logMsg(msgLog, 1, 2)

    rules = moduleRules()
    srcs, dsts, ruls, impRuls = rules.checkRules()

    rules.printList(srcs, "Sources")
    rules.printList(dsts, "Destinations")
    print("Rules")
    for i,rul in enumerate(sorted(ruls)):
        print(f"{i}) {rul}")
        for j, action in enumerate(ruls[rul]):
                print(f"   └---->{j}) {action}")

    return
Пример #2
0
    def readConfigSrc(self, indent, src, more):
        msgLog = f"Src: Src {src}"
        logMsg(msgLog, 2, 0)
        msgLog = f"More: Src {more}"
        logMsg(msgLog, 1, 0)
        if src[0] == 'cache':
            apiSrc = getApi(src[0], src[1:])
            apiSrc.fileName = apiSrc.fileNameBase(src[1:])
            apiSrc.postaction = 'delete'
        else:
            apiSrc = getApi(src[0], src[2])

        for option in more:
            if option == 'posts':
                nameMethod = f"setPostsType"
            else:
                nameMethod = f"set{option.capitalize()}"

            if  nameMethod in apiSrc.__dir__():
                # setCache ¿?
                # url, time, max, posts,
                cmd = getattr(apiSrc, nameMethod)
                if inspect.ismethod(cmd):
                    cmd(more[option])
            else:
                for name in apiSrc.__dir__():
                    if name.lower() == nameMethod.lower():
                        cmd = getattr(apiSrc, name)
                        if inspect.ismethod(cmd):
                            cmd(more[option])
                            break

        if not apiSrc.getPostsType():
            apiSrc.setPostsType('posts')

        # apiSrc.setPosts()
        # print(f"Postsss: {apiSrc.getPosts()}")
        return apiSrc
Пример #3
0
    def hasPublishMethod(self, service):
        clsService = getModule(service)
        listMethods = clsService.__dir__()

        methods = []
        target = None
        for method in listMethods:
            if method.find("publish") >= 0:
                action = "publish"
                target = ""
                moduleService = clsService.publishPost.__module__
                if method.find("Api") >= 0:
                    target = method[len("publishApi"):].lower()
                    msgLog = (f"Target api {target}")
                    logMsg(msgLog, 2, 0)
                elif moduleService == f"module{service.capitalize()}":
                    target = method[len("publish"):].lower()
                    msgLog = (f"Target mod {target}")
                    logMsg(msgLog, 2, 0)
                if target and (target!='image'):
                    toAppend = (action, target)
                    if not (toAppend in methods):
                        methods.append(toAppend)
        return methods
Пример #4
0
    def readConfigDst(self, indent, action, more, apiSrc):
        profile = action[2]
        nick = action[3]
        socialNetwork = (profile, nick)
        msgLog = (f"{indent}socialNetwork: {socialNetwork}")
        logMsg(msgLog, 2, 0)
        msgLog = (f"{indent}Action: {action}")
        logMsg(msgLog, 1, 0)
        msgLog = (f"{indent}More: Dst {more}")
        logMsg(msgLog, 1, 0)

        if action[0] == "cache":
            print(f"Dst: {action}")
            apiDst = getApi("cache", ((more['service'],  action[1]), 
                f"{action[2]}@{action[3]}", 'posts'))
            apiDst.socialNetwork = action[2]
            apiDst.nick = action[3]
            apiDst.fileName = apiDst.fileNameBase(apiSrc)
        else:
            apiDst = getApi(profile, nick)

        apiDst.setUser(nick)
        apiDst.setPostsType('posts')

        msgLog = (f"{indent}Api dst: {apiDst}")
        logMsg(msgLog, 2, 0)

        if 'max' in more:
            mmax = more['max']
        elif 'buffermax' in more:
            mmax = more['buffermax']
        else:
            mmax = 0

        apiDst.setMax(mmax)

        if 'time' in more:
            apiDst.setTime(more['time'])

        return apiDst
Пример #5
0
    def checkRules(self):
        msgLog = "Checking rules"
        logMsg(msgLog, 1, 2)
        config = configparser.ConfigParser()
        config.read(CONFIGDIR + "/.rssBlogs")

        services = self.getServices()
        services['regular'].append('cache')
        # cache objects can be considered as regular for publishing elements
        # stored there
        indent = 3*"  "+4*" "

        srcs = []
        srcsA = []
        more = []
        dsts = []
        ruls = {}
        mor = {}
        impRuls = []
        for section in config.sections():
            url = config.get(section, "url")
            msgLog = f"Section: {section} Url: {url}"
            logMsg(msgLog, 1, 1)
            # Sources
            moreS = dict(config.items(section))
            moreSS = None
            if "rss" in config.options(section):
                rss = config.get(section, "rss")
                msgLog = (f"Service: rss -> {rss}")
                logMsg(msgLog, 2, 0)
                toAppend = ("rss", "set",
                            urllib.parse.urljoin(url, rss), "posts")
                srcs.append(toAppend)
                more.append(moreS)
            else:
                msgLog = (f"url {url}")
                logMsg(msgLog, 2, 0)

                for service in services["regular"]:
                    if (
                        ("service" in config[section])
                        and (service == config[section]["service"])
                    ) or (url.find(service) >= 0):
                        methods = self.hasSetMethods(service)
                        logging.debug(f"Service: {service} has set {methods}")
                        for method in methods:
                            msgLog = (f"Method: {method}")
                            logMsg(msgLog, 2, 0)
                            msgLog = (f"moreS: {moreS}")
                            logMsg(msgLog, 2, 0)
                            # If it has a method for setting, we can set
                            # directly using this
                            if service in config[section]:
                                nick = config[section][service]
                            else:
                                nick = url
                                if ((nick.find("slack") < 0)
                                        and (nick.find("gitter") < 0)):
                                    nick = nick.split("/")[-1]
                            if (service == 'imdb') or (service == 'imgur'):
                                nick = url
                            elif ('twitter' in url):
                                nick = url.split("/")[-1]

                            if 'posts' in moreS:
                                if moreS['posts'] == method[1]:
                                   toAppend = (service, "set", nick, method[1])
                            else:
                               toAppend = (service, "set", nick, method[1])
                            msgLog = (f"toAppend: {toAppend}")
                            logMsg(msgLog, 2, 0)
                            if not (toAppend in srcs):
                                if (('posts' in moreS)
                                    and (moreS['posts'] == method[1])):
                                    srcs.append(toAppend)
                                    more.append(moreS)
                                else:
                                    # Available, but with no rules
                                    srcsA.append(toAppend)
            fromSrv = toAppend
            msgLog = (f"fromSrv toAppend: {toAppend}")
            logMsg(msgLog, 2, 0)
            msgLog = (f"fromSrv moreS: {moreS}")
            logMsg(msgLog, 2, 0)

            if "time" in config.options(section):
                timeW = config.get(section, "time")
            else:
                timeW = 0
            if "buffermax" in config.options(section):
                bufferMax = config.get(section, "buffermax")
            else:
                bufferMax = 0
            if "max" in config.options(section):
                bufferMax = config.get(section, "max")

            # Destinations
            hasSpecial = False
            if "posts" in config[section]:
                postsType = config[section]["posts"]
            else:
                postsType = "posts"
            if fromSrv:
                fromSrv = ( fromSrv[0], fromSrv[1], fromSrv[2], postsType,)
                for service in services["special"]:
                    toAppend = ""
                    msgLog = (f"Service: {service}")
                    logMsg(msgLog, 2, 0)
                    if service in config.options(section):
                        valueE = config.get(section, service).split("\n")
                        for val in valueE:
                            nick = config.get(section, val)
                            msgLog = (f"Service special: {service} "
                                      f"({val}, {nick})")
                            logMsg(msgLog, 2, 0)
                            if service == "direct":
                                url = "posts"
                            toAppend = (service, url, val, nick) #, timeW, bufferMax)
                            msgLog = (f"Service special toAppend: {toAppend} ")
                            logMsg(msgLog, 2, 0)
                            msgLog = (f"Service special from: {fromSrv} ")
                            logMsg(msgLog, 2, 0)
                            if toAppend not in dsts:
                                dsts.append(toAppend)
                            if toAppend:
                                if fromSrv not in mor:
                                    mor[fromSrv] = moreS
                                if fromSrv in ruls:
                                    if not toAppend in ruls[fromSrv]:
                                        ruls[fromSrv].append(toAppend)
                                        msgLog = (f"1 added: {toAppend} "
                                                  f"in {fromSrv} ")
                                        logMsg(msgLog, 2, 0)
                                else:
                                    ruls[fromSrv] = []
                                    ruls[fromSrv].append(toAppend)
                                    msgLog = (f"1.1 added: {toAppend} "
                                              f"in {fromSrv} ")
                                    logMsg(msgLog, 2, 0)

                                hasSpecial = True

                for service in services["regular"]:
                    if (service == 'cache'):
                        continue
                    toAppend = ""
                    if service in config.options(section):
                        methods = self.hasPublishMethod(service)
                        msgLog = (f"Service: {service} ({section}) has "
                                  f"{methods}")
                        logMsg(msgLog, 2, 0)
                        for method in methods:
                            msgLog = (f"Method: {method}")
                            logMsg(msgLog, 2, 0)
                            # If it has a method for publishing, we can
                            # publish directly using this

                            if not method[1]:
                                mmethod = 'post'
                            else:
                                mmethod = method[1]
                            toAppend = (
                                    "direct",
                                    mmethod,
                                    service,
                                    config.get(section, service) #,
                                    # timeW,
                                    # bufferMax,
                                    )

                            if not (toAppend in dsts):
                                dsts.append(toAppend)
                            if toAppend:
                                if hasSpecial:
                                    msgLog = (f"hasSpecial: {fromSrv}---")
                                    logMsg(msgLog, 2, 0)
                                    msgLog = (f"hasSpecial: {toAppend}---")
                                    logMsg(msgLog, 2, 0)
                                    nickSn = f"{toAppend[2]}@{toAppend[3]}"
                                    fromSrvSp = (
                                            "cache",
                                            (fromSrv[0], fromSrv[2]),
                                            nickSn,
                                            "posts",
                                            )
                                    impRuls.append((fromSrvSp, toAppend))
                                    if fromSrvSp not in mor:
                                        mor[fromSrvSp] = moreS
                                    if fromSrvSp in ruls:
                                        if not toAppend in ruls[fromSrvSp]:
                                            ruls[fromSrvSp].append(toAppend)
                                            msgLog = (f"2 added: {toAppend} "
                                                      f"in {fromSrvSp} ")
                                            logMsg(msgLog, 1, 0)
                                    else:
                                        ruls[fromSrvSp] = []
                                        ruls[fromSrvSp].append(toAppend)
                                        if url:
                                            msgLog = (f"2.1 added: {toAppend} "
                                                      f"in {fromSrvSp} "
                                                      f"with {url}")
                                        else:
                                            msgLog = (f"2.1 added: {toAppend} "
                                                      f"in {fromSrvSp} "
                                                      f"with no url")
                                        logMsg(msgLog, 1, 0)
                                else:
                                    msgLog = (f"From {fromSrv}")
                                    logMsg(msgLog, 2, 0)
                                    msgLog = (f"direct: {dsts}---")
                                    logMsg(msgLog, 2, 0)

                                    if fromSrv not in mor:
                                        msgLog = (f"Adding {moreS}")
                                        logMsg(msgLog, 2, 0)
                                        mor[fromSrv] = moreS
                                    if fromSrv in ruls:
                                        if not toAppend in ruls[fromSrv]:
                                            ruls[fromSrv].append(toAppend)
                                            msgLog = (f"3 added: {toAppend} in "
                                                      f"{fromSrv} ")
                                            logMsg(msgLog, 2, 0)
                                    else:
                                        ruls[fromSrv] = []
                                        ruls[fromSrv].append(toAppend)
                                        msgLog = (f"3.1 added: {toAppend} in "
                                                  f"{fromSrv} ")
                                        logMsg(msgLog, 2, 0)

        # Now we can add the sources not added.

        for src in srcsA:
            if not src in srcs:
                msgLog = (f"Adding implicit {src}")
                logMsg(msgLog, 2, 0)
                srcs.append(src)
                more.append({})

        # Now we can see which destinations can be also sources
        for dst in dsts:
            if dst[0] == "direct":
                service = dst[2]
                methods = self.hasSetMethods(service)
                for method in methods:
                    msgLog = (f"cache dst {dst}")
                    logMsg(msgLog, 2, 0)
                    toAppend = (service, "set", dst[3], method[1])#, dst[4])
                    msgLog = (f"toAppend src {toAppend}")
                    logMsg(msgLog, 2, 0)
                    if not (toAppend[:4] in srcs):
                        srcs.append(toAppend[:4])
                        more.append({})
            elif dst[0] == "cache":
                if len(dst)>4 :
                    toAppend = (dst[0], "set", (dst[1], (dst[2], dst[3])),
                                "posts", dst[4], 1)
                else:
                    toAppend = (dst[0], "set", (dst[1], (dst[2], dst[3])),
                                "posts", 0, 1)
                if not (toAppend[:4] in srcs):
                        srcs.append(toAppend[:4])
                        more.append({})

        available = {}
        myKeys = {}
        myIniKeys = []
        # for i, src in enumerate(srcs):
        for i, src in enumerate(ruls.keys()):
            if not src:
                continue
            iniK, nameK = self.getIniKey(src[0], myKeys, myIniKeys)
            if not (iniK in available):
                available[iniK] = {"name": src[0], "data": [], "social": []}
                available[iniK]["data"] = [{'src': src[1:], 'more': more[i]}]
            else:
                available[iniK]["data"].append({'src': src[1:],
                                                'more': more[i]})
            # srcC = (src[0], "set", src[1], src[2])
            # if srcC not in ruls:
            #     ruls[srcC] =

        myList = []
        for elem in available:
            component = (
                f"{elem}) "
                f"{available[elem]['name']}: "
                f"{len(available[elem]['data'])}"
            )
            myList.append(component)

        if myList:
            availableList = myList
        else:
            availableList = []

        self.available = available
        self.availableList = availableList

        msgLog = (f"Avail: {self.available}")
        logMsg(msgLog, 2, 0)
        msgLog = (f"Ruls: {ruls}")
        logMsg(msgLog, 2, 0)
        self.rules = ruls
        self.more = mor

        return (srcs, dsts, ruls, impRuls)
Пример #6
0
    def executeRules(self, args):
        msgLog = "Execute rules"
        logMsg(msgLog, 1, 2)

        # print(args)
        select = args.checkBlog
        simmulate = args.simmulate

        import concurrent.futures

        delayedPosts = []
        # import pprint
        # pprint.pprint(self.rules)
        # textEnd = ""

        threads = 0
        with concurrent.futures.ThreadPoolExecutor(max_workers=75) as pool:
            i = 0
            previous = ""

            for src in sorted(self.rules.keys()):
                if src[0] != previous:
                    i = 0
                previous = src[0]
                name = f"{src[0]}{i}>"
                if src in self.more:
                    # f"  More: {self.more[src]}")
                    more = self.more[src]
                else:
                    # f"  More: empty")
                    more = None

                if src[0] in ['cache', 'gitter', 'gmail']:
                    srcName = more['url']
                    # FIXME 
                    if 'slack' in srcName:
                        srcName = f"Slack({srcName.split('/')[2].split('.')[0]})"
                    elif 'gitter' in srcName:
                        srcName = f"Gitter({srcName.split('/')[-2]})"
                    elif 'imgur' in srcName:
                        srcName = f"Imgur({srcName.split('/')[-1]})"
                    elif '.com' in srcName:
                        srcName = f"Gmail({srcName.split('.')[0]})"
                    text = (f"Source: {srcName} ({src[3]})")
                else:
                    text = (f"Source: {src[2]} ({src[3]})")
                textEnd = (f"Source: {name} {src[2]} {src[3]}")

                actions = self.rules[src]

                for k, action in enumerate(actions):
                    if (select and (select.lower() != f"{src[0].lower()}{i}")):
                        actionMsg = f"Skip."
                    else:
                        actionMsg = (f"Scheduling...")
                    nameA = f"{name} {actionMsg} "
                    if action[1].startswith('http'):
                        # FIXME
                        theAction = 'posts'
                    else:
                        theAction = action[1]

                    msgLog = (f"{nameA} {text} Action {k}:"
                              f" {action[3]}@{action[2]} ({theAction})")
                    textEnd = f"{textEnd}\n{msgLog}"
                    logMsg(msgLog, 1, 1)
                    nameA = f"{name} [({theAction})"
                    # The '[' is closed in executeAction TODO
                    if actionMsg == "Skip.":
                        continue
                    timeSlots = args.timeSlots
                    noWait = args.noWait

                    # Is this the correct place?
                    if ((action[0] in 'cache') or
                        ((action[0] == 'direct') and (action[2] == 'pocket'))
                        ):
                        # We will always load new items in the cache
                        timeSlots = 0
                        noWait=True

                    threads = threads + 1
                    delayedPosts.append(pool.submit(self.executeAction,
                                        src, more, action,
                                        noWait,
                                        timeSlots,
                                        args.simmulate,
                                        nameA))
                i = i + 1

            messages = []
            for future in concurrent.futures.as_completed(delayedPosts):
                try:
                    res = future.result()
                    msgLog = (f"End Delay: {res}")
                    logMsg(msgLog, 1, 1)
                    if res:
                        messages.append(
                                f"  Published in: {future}\n{res} "
                                )
                except Exception as exc:
                #else:
                    msgLog = (f"{future} generated an exception: {exc} "
                                 f"Src: {src}. Action: {action}")
                    logMsg(msgLog, 1, 1)
                    msgLog = (f"{sys.exc_info()}")
                    logMsg(msgLog, 1, 1)
                    import traceback
                    msgLog = (f"{traceback.print_exc()}")
                    logMsg(msgLog, 1, 1)


        msgLog = (f"End Execute rules with {threads} threads.")
        logMsg(msgLog, 1, 2)

        return
Пример #7
0
    def executeAction(self, src, more, action,
                    noWait, timeSlots, simmulate, name="",
                    nextPost = True, pos = -1, delete=False):

        sys.path.append(path)
        from configMod import logMsg

        indent = f"    {name}->({action[3]}@{action[2]})] -> "+" "
        # The ']' is opened in executeRules FIXME

        msgLog = (f"{indent}Sleeping to launch all processes")
        logMsg(msgLog, 1, 0)
        # 'Cometic' waiting to allow all the processes to be launched.
        time.sleep(1)

        msgAction = (f"{action[0]} {action[3]}@{action[2]} "
                     f"({action[1]})")
        # Destination

        apiSrc = self.readConfigSrc(indent, src, more)

        if apiSrc.getName(): 
            msgLog = (f"{indent}Source: {apiSrc.getName()} ({src[3]}) -> "
                f"Action: {msgAction})")
        else:
            msgLog = (f"{indent}Source: {src[2]} ({src[3]}) -> "
                f"Action: {msgAction})")

        logMsg(msgLog, 1, 0)
        textEnd = (f"{msgLog}")

        # print(f"Srcccc: {src}")
        # print(f"Srcccc: {apiSrc.getNick()}")
        # return
        if (apiSrc.getHold() == 'yes'):
            time.sleep(1)
            msgHold = f"{indent} In hold"
            logging.info(msgHold)
            return msgHold
        if not apiSrc.getClient():
            msgLog = (f"{indent}Error. No client for {src[2]} ({src[3]})")
            logMsg(msgLog, 1, 1)
            return f"End: {msgLog}"

        apiSrc.setPosts()

        # print(f"apiSrc: {apiSrc}")
        # print(f"action: {action}")
        # print(f"more {more}")
        apiDst = self.readConfigDst(indent, action, more, apiSrc)
        if not apiDst.getClient():
            msgLog = (f"{indent}Error. No client for {action[2]}")
            logMsg(msgLog, 1, 1)
            return f"End: {msgLog}"

        apiDst.setUrl(apiSrc.getUrl())

        # print(f"{indent}action: {action}")
        # print(f"-->{indent}apiDst: {apiDst.getPostsType()} {action[1]}")
        # print(f"-->{indent}apiDst: {apiDst.getPostsType()[:-1]} {action[1]}")

        # print(f"-->{indent}apiDst: {apiDst.getPostsType()} {action[1]}")
        if ((apiDst.getPostsType() != action[1])
            and (apiDst.getPostsType()[:-1] != action[1])
            and (action[0] != 'cache')):
            # FIXME: Can we do better?
            return f"{indent}{action}"

        apiDst.setPosts()
        # print(f"Posttttts: {apiDst.getPosts()}")
        #FIXME: Is it always needed? Only in caches?

        indent = f"{indent} "

        apiSrc.setLastLink(apiDst)

        lastLink = apiSrc.getLastLinkPublished()
        lastTime = apiSrc.getLastTimePublished()

        time.sleep(1)
        if lastLink:
            msgLog = (f"Last link: {lastLink} ")
            logMsg(f"{indent}{msgLog}", 1, 1)

        msgLog = ''
        if lastTime:
            myTime = time.strftime("%Y-%m-%d %H:%M:%S",
                                    time.localtime(lastTime))

            msgLog = (f"{msgLog}Last time: {myTime}")

        if nextPost:
            num = apiDst.getMax()
        else:
            num = 1

        msgLog = (f"{indent}{msgLog} Num: {num}")
        logMsg(msgLog, 1, 1)

        listPosts = []
        link = ''

        if (num > 0):
            tNow = time.time()
            hours = float(apiDst.getTime())*60*60

            if lastTime:
                diffTime = tNow - lastTime
            else:
                # If there is no lasTime, we will publish
                diffTime = hours + 1

            msgLog = (f"{indent}Src time: {apiSrc.getTime()} "
                      f"Dst time: {apiDst.getTime()}")
            logMsg(msgLog, 2, 0)

            numAvailable = 0

            if (noWait or (diffTime>hours)):
                tSleep = random.random()*float(timeSlots)*60

                if nextPost:
                    post = apiSrc.getNextPost()
                else:
                    post = apiSrc.getPost(pos)

                if post:
                    apiSrc.setNextTime(tNow, tSleep, apiDst)
                else:
                    apiSrc.setNextAvailableTime(tNow, tSleep, apiDst)

                if (tSleep>0.0):
                    msgLog= f"{indent}Waiting {tSleep/60:2.2f} minutes"
                else:
                    tSleep = 2.0
                    msgLog= f"{indent}No Waiting"

                msgLog = f"{msgLog} for action: {msgAction}"
                logMsg(msgLog, 1, 1)

                for i in range(num):
                    time.sleep(tSleep)
                    if nextPost:
                        self.executePublishAction(indent, msgAction, apiSrc,
                                                apiDst, simmulate)
                    else:
                        self.executePublishAction(indent, msgAction, apiSrc,
                                                apiDst, simmulate, 
                                                nextPost, pos)

            elif (diffTime<=hours):
                msgLog = (f"Not enough time passed. "
                          f"We will wait at least "
                          f"{(hours-diffTime)/(60*60):2.2f} hours.")
                # logMsg(msgLog, 1, 1)
                textEnd = f"{textEnd} {msgLog}"

        else:
            if (num<=0):
                msgLog = (f"{indent}No posts available")
                logMsg(msgLog, 1, 1)

        return textEnd
Пример #8
0
    def executePublishAction(self, indent, msgAction, apiSrc, apiDst, 
                            simmulate, nextPost=True, pos=-1):
        res = ''

        msgLog = (f"{indent}Go! Action: {msgAction}")
        logMsg(msgLog, 1, 1)

        # The source of data can have changes while we were waiting
        apiSrc.setPosts()
        if nextPost:
            # FIXME is  this needed?
            post = apiSrc.getNextPost()
        else:
            post = apiSrc.getPost(pos)

        if post:
            msgLog = f"{indent}Would schedule in {msgAction} ..."
            logMsg(msgLog, 1, 1)
            indent = f"{indent} "
            logMsg(msgLog, 2, 0)
            logMsg(f"{indent}- {apiSrc.getPostTitle(post)}", 1, 1)
        else:
            msgLog = f"{indent}No post to schedule in {msgAction}"
            logMsg(msgLog, 1, 1)

        indent = f"{indent[:-1]}"

        resMsg = ''
        postaction = ''
        if not simmulate:
            if nextPost:
                res = apiDst.publishNextPost(apiSrc)
            else:
                res = apiDst.publishPosPost(apiSrc, pos)
            resMsg = f"Publish: {res}. "
            # print(f"{indent}res: {res}")
            if (nextPost and 
                    ((not res) or ('SAVELINK' in res) or not ('Fail!' in res))):
                resUpdate = apiSrc.updateLastLink(apiDst, '')
                resMsg += f"Update: {resUpdate}"
            if ((not res) or ('SAVELINK' in res) or not ('Fail!' in res)):
                postaction = apiSrc.getPostAction()
                if postaction:
                    msgLog = (f"{indent}Post Action {postaction}")
                    logMsg(msgLog, 1, 1)

                    if nextPost:
                        cmdPost = getattr(apiSrc, f"{postaction}NextPost")
                        resPost = cmdPost()
                    else:
                        cmdPost = getattr(apiSrc, f"{postaction}")
                        resPost = cmdPost(pos)
                        # FIXME inconsistent
                    msgLog = (f"{indent}Post Action command {cmdPost}")
                    logMsg(msgLog, 1, 1)
                    msgLog = (f"{indent}End {postaction}, reply: {resPost} ")
                    logMsg(msgLog, 1, 1)
                    resMsg += f"Post Action: {resPost}"
                else:
                    msgLog = (f"{indent}No Post Action")
                    logMsg(msgLog, 1, 1)

            msgLog = (f"{indent}End publish, reply: {resMsg}")
            logMsg(msgLog, 1, 1)
        else:
            msgLog = (f"{indent}This is a simmulation")
            logMsg(msgLog, 1, 1)
            resMsg = f"Simulate: {msgLog}\n"
            post = apiSrc.getNextPost()
            if post:
                link = apiSrc.getPostLink(post)
                if link:
                    msgLog = (f"{indent}I'd record link: {link}")
                    logMsg(msgLog, 1, 1)
                    resMsg += f"{msgLog}\n"
                    # fN = fileNamePath(apiDst.getUrl(), socialNetwork)
                    # msgLog = (f"{indent}in file ", f"{fN}.last")
                    # logMsg(msgLog, 1, 1)
                    msgLog = (f"{indent}in file "
                              f"{apiSrc.fileNameBase(apiDst)}.last")
                    logMsg(msgLog, 1, 1)
                    resMsg += f"{msgLog}\n"
        if postaction == 'delete':
            msgLog = (f"{indent}Available {len(apiSrc.getPosts())-1}")
        else:
            msgLog = (f"{indent}Available {len(apiSrc.getPosts())}")
        logMsg(msgLog, 1, 1)

        return resMsg