Esempio n. 1
0
# Get entries in Anilist, not on your Tachiyomi library
# imports
import os
import json
from google import protobuf
# Local import
import func.main as fMain
from func import tachiBackup_pb2 as tachiBackupProto

fMain.logString("Imported func.getNotOnTachi", "")


# Functions
def logString(text):
    fMain.logString(text, "getNotOnTachi")


def sort_byval(json):
    try:
        return str(json['format'])
    except KeyError:
        return ""


# Open json tachiyomi backup file, and load all Anilist-tracked entries
def parseLegacyBackup(inputMangaPath: str) -> list:
    listReturn = []
    loadTachi = None
    logString("Loading legacy backup '" + os.path.basename(inputMangaPath) +
              "' into memory..")
    with open(inputMangaPath, "r+", encoding='utf-8') as F:
Esempio n. 2
0
def logString(text):
    fMain.logString(text, "getNotOnTachi")
Esempio n. 3
0
def trim_results(filepath, inputAnime, inputManga, isNsfw):
    # Declare filepaths
    if isNsfw:
        outputStats = os.path.join(filepath, "output", f'nsfw_animemanga_stats.txt')
    else:
        outputStats = os.path.join(filepath, "output", f'animemanga_stats.txt')

    outputAnime = f'{inputAnime[:-5]}_NotInMAL.json'
    outputManga = f'{inputManga[:-5]}_NotInMAL.json'
    # STATS variables
    statScoreTotal = 0
    statScoreCount = 0
    statInMAL = 0
    # Count entries
    cTotal = 0
    cCurrent = 0
    cComplete = 0
    cHold = 0
    cDrop = 0
    cPlan = 0

    # Delete prev files
    fMain.deleteFile(outputStats)

    # Load JSON objects
    # Check if anime file Exists!
    if not (os.path.exists(inputAnime)):
        fMain.logString("Anime json file does not exists!", logSrc)
        jsonAnime = None
    else:
        fMain.logString("Loading " + os.path.basename(inputAnime) + " into memory..", logSrc)
        with open(inputAnime, "r+", encoding='utf-8') as F:
            jsonAnime = json.load(F)
            jsonAnime.sort(key=sort_byval, reverse=True)
            fMain.logString("Anime json file loaded!", logSrc)
    # Check if manga file Exists!
    if not (os.path.exists(inputManga)):
        fMain.logString("Manga json file does not exists!", logSrc)
        jsonManga = None
    else:
        fMain.logString("Loading " + os.path.basename(inputManga) + " into memory..", logSrc)
        with open(inputManga, "r+", encoding='utf-8') as F:
            jsonManga = json.load(F)
            jsonManga.sort(key=sort_byval, reverse=True)
            fMain.logString("Manga json file loaded!", logSrc)

    # json Objects
    jsonOutputAnime = []
    jsonOutputManga = []

    # Get entries from Anime, not in MAL
    if jsonAnime is not None:
        fMain.logString("Checking anime list..", logSrc)
        for entry in jsonAnime:
            # Get each entry
            if (entry["idMal"] < 1):
                # If not in MAL, ID = 0
                statInMAL += 1
                jsonData = {}
                jsonData["idAnilist"] = entry["idAnilist"]
                jsonData["titleEnglish"] = entry["titleEnglish"]
                jsonData["titleRomaji"] = entry["titleRomaji"]
                if str(entry["synonyms"]) == "[]":
                    jsonData["synonyms"] = ""
                else:
                    jsonData["synonyms"] = entry["synonyms"]
                jsonData["format"] = entry["format"]
                jsonData["source"] = entry["source"]
                jsonData["status"] = entry["status"]
                jsonData["startedAt"] = entry["startedAt"]
                jsonData["completedAt"] = entry["completedAt"]
                jsonData["progress"] = entry["progress"]
                jsonData["totalEpisodes"] = entry["totalEpisodes"]
                jsonData["score"] = entry["score"]
                jsonData["notes"] = entry["notes"]
                # Append to JSON object
                jsonOutputAnime.append(jsonData)

            # Stats checker
            statScore = int(entry["score"])
            if (statScore > 0):
                statScoreTotal = statScoreTotal + statScore
                statScoreCount = statScoreCount + 1
            
            # Count entries
            AnilistStatus = str(entry["status"])
            if (AnilistStatus == "COMPLETED"):
                cComplete = cComplete + 1
            elif (AnilistStatus == "PAUSED"):
                cHold = cHold + 1
            elif (AnilistStatus == "CURRENT"):
                cCurrent = cCurrent + 1
            elif (AnilistStatus == "DROPPED"):
                cDrop = cDrop + 1
            elif (AnilistStatus == "PLANNING"):
                cPlan = cPlan + 1
            elif (AnilistStatus == "REPEATING"):
                cCurrent = cCurrent + 1

        # Write 'outputAnime'
        if jsonOutputAnime:
            fMain.createJsonFile(outputAnime, jsonOutputAnime, logSrc)

        # Write stats for Anime
        cTotal = cComplete + cCurrent + cHold + cPlan + cDrop
        fMain.logString("Appending to file (Average Score stats): " + os.path.basename(outputStats), logSrc)
        averageScore = "{:.2f}".format(statScoreTotal/statScoreCount * 10)
        fMain.write_append(outputStats, "Anime stats:\nAverage Score (out of 100): " + averageScore + "\n")
        fMain.write_append(outputStats, "Count:\nCompleted: " + str(cComplete) + "\nCurrently Watching: " + str(cCurrent) + "\nPaused: " + str(cHold) + "\nPlanning: " + str(cPlan) + "\nDropped: " + str(cDrop) + "\n")
        fMain.write_append(outputStats, "\nTotal: " + str(cTotal))
        fMain.write_append(outputStats, "\nAnime Not in MAL: " + str(statInMAL) + "\n")

    # Add Line Break
    fMain.write_append(outputStats, "=========================================\n")
    # Reset vars
    statScoreTotal = 0
    statScoreCount = 0
    statInMAL = 0
    # Reset count
    cTotal = 0
    cCurrent = 0
    cComplete = 0
    cHold = 0
    cDrop = 0
    cPlan = 0

    # For MANGA
    # Get entries from MANGA, not in MAL
    if jsonManga is not None:
        fMain.logString("Checking manga list..", logSrc)
        for entry in jsonManga:
            # Get each entry
            if (entry["idMal"] < 1):
                # If not in MAL, ID = 0
                statInMAL += 1
                jsonData = {}
                jsonData["idAnilist"] = entry["idAnilist"]
                jsonData["titleEnglish"] = entry["titleEnglish"]
                jsonData["titleRomaji"] = entry["titleRomaji"]
                if str(entry["synonyms"]) == "[]":
                    jsonData["synonyms"] = ""
                else:
                    jsonData["synonyms"] = entry["synonyms"]
                jsonData["format"] = entry["format"]
                jsonData["source"] = entry["source"]
                jsonData["status"] = entry["status"]
                jsonData["startedAt"] = entry["startedAt"]
                jsonData["completedAt"] = entry["completedAt"]
                jsonData["progress"] = entry["progress"]
                jsonData["progressVolumes"] = entry["progressVolumes"]
                jsonData["totalChapters"] = entry["totalChapters"]
                jsonData["totalVol"] = entry["totalVol"]
                jsonData["score"] = entry["score"]
                jsonData["notes"] = entry["notes"]
                # Append to JSON object
                jsonOutputManga.append(jsonData)

            # Stats checker
            statScore = int(entry["score"])
            if (statScore > 0):
                statScoreTotal = statScoreTotal + statScore
                statScoreCount = statScoreCount + 1

            # Count entries
            AnilistStatus = str(entry["status"])
            if (AnilistStatus == "COMPLETED"):
                cComplete = cComplete + 1
            elif (AnilistStatus == "PAUSED"):
                cHold = cHold + 1
            elif (AnilistStatus == "CURRENT"):
                cCurrent = cCurrent + 1
            elif (AnilistStatus == "DROPPED"):
                cDrop = cDrop + 1
            elif (AnilistStatus == "PLANNING"):
                cPlan = cPlan + 1
            elif (AnilistStatus == "REPEATING"):
                cCurrent = cCurrent + 1
                
        # Write 'outputManga'
        if jsonOutputManga:
            fMain.createJsonFile(outputManga, jsonOutputManga, logSrc)

        # Write stats for Manga
        cTotal = cComplete + cCurrent + cHold + cPlan + cDrop
        fMain.logString("Appending to file (Average Score stats): " + os.path.basename(outputStats), logSrc)
        averageScore = "{:.2f}".format(statScoreTotal/statScoreCount * 10)
        fMain.write_append(outputStats, "Manga stats:\nAverage Score (out of 100): " + averageScore + "\n")
        fMain.write_append(outputStats, "Count:\nCompleted: " + str(cComplete) + "\nCurrently Reading: " + str(cCurrent) + "\nPaused: " + str(cHold) + "\nPlanning: " + str(cPlan) + "\nDropped: " + str(cDrop) + "\n")
        fMain.write_append(outputStats, "\nTotal: " + str(cTotal))
        fMain.write_append(outputStats, "\nManga Not in MAL: " + str(statInMAL) + "\n")
Esempio n. 4
0
# Remove Entries that have MAL ID
# And additional code to get stats
# imports
import os
import json
# Local imports
import func.main as fMain

# Other vars
logSrc = "trim_list"
fMain.logString("Imported func.trim_list", "")

# Functions
def sort_byval(json):
    try:
        return str(json['format'])
    except KeyError:
        return ""

def trim_results(filepath, inputAnime, inputManga, isNsfw):
    # Declare filepaths
    if isNsfw:
        outputStats = os.path.join(filepath, "output", f'nsfw_animemanga_stats.txt')
    else:
        outputStats = os.path.join(filepath, "output", f'animemanga_stats.txt')

    outputAnime = f'{inputAnime[:-5]}_NotInMAL.json'
    outputManga = f'{inputManga[:-5]}_NotInMAL.json'
    # STATS variables
    statScoreTotal = 0
    statScoreCount = 0
Esempio n. 5
0
def main():
  # Declare variables
  fMain.logString("Define Global Vars..", mainsrc)
  # Paths for Files
  PROJECT_PATH = os.path.dirname(os.path.realpath(__file__)) #os.path.dirname(sys.executable)
  fMain.logString("Current path: " + PROJECT_PATH, mainsrc)
  anilistConfig = os.path.join(PROJECT_PATH, "anilistConfig.json")
  entryLog = os.path.join(PROJECT_PATH, "output", "entries.log") # Log entries
  # Vars for Authentication
  ANICLIENT = ""
  ANISECRET = ""
  useOAuth = False
  # User vars
  username = ""
  userID = 0
  isSepNsfw = False # Separate nsfw entries on output
  # Output files dictionary
  outputAnime = []
  outputManga = []

  # Create 'output' directory
  if not os.path.exists('output'):
      os.makedirs('output')

  # Toggle when skipping Public mode, or Authenticated mode
  inputChoice = fMain.inputX("Use Authenticated mode? [y/n] (Default: 'Public List mode'): ", "n")

  if inputChoice.lower()[0] == "y":
    # Import config for Anilist OAuth
    fMain.logString("Importing Anilist config", mainsrc)
    
    useOAuth, ANICLIENT, ANISECRET, REDIRECT_URL = fReq.setup_config(anilistConfig)

    if not useOAuth:
      accessToken = ""
    
    if useOAuth:
      code = fReq.request_pubcode(ANICLIENT, REDIRECT_URL)
      accessToken = fReq.request_accesstkn(ANICLIENT, ANISECRET, REDIRECT_URL, code)

    if accessToken:
      useOAuth = True
      fMain.logString("Has access token!", mainsrc)
    else:
      useOAuth = False
      fMain.logString("Cannot Authenticate! Will use Public Username.", mainsrc)
  else:
    useOAuth = False


  # Check whether authenticated, or use public Username
  if not useOAuth:
    fMain.logString("'Public Username' Mode", mainsrc)
    accessToken = ""
    while (userID < 1):
      # Get Anilist Username
      anilistUser = fMain.inputX("Enter your Anilist Username: "******"")
      userID = fReq.anilist_getUserID(anilistUser)
  else:
    fMain.logString("Getting User ID, from Authenticated user..", mainsrc)
    userID = fReq.anilist_getUserID_auth(accessToken)
    if userID is not None:
      fMain.logString("User ID: " + str(userID), mainsrc)
    else:
      fMain.logString("User Id cannot be fetched!", mainsrc)

  # Confirm if separating nsfw entries on generating output files
  inputChoice = fMain.inputX("Separate NSFW entries? [y/n] (Default: n): ", "n")

  if inputChoice.lower()[0] == "y":
    isSepNsfw = True

  # Delete prev files
  fMain.deleteFile(entryLog)

  # Initiate parameter values
  paramvals = {
      'root': PROJECT_PATH,
      'log': entryLog,
      'access_tkn': accessToken,
      'user_id': userID,
      'username': username,
      'use_auth': useOAuth,
      'sep_nsfw': isSepNsfw
  }

  # Request anime list
  outputAnime = getMediaEntries("ANIME", paramvals)

  # Request manga list
  outputManga = getMediaEntries("MANGA", paramvals)

  # Trim List
  tempTrim = fMain.inputX("Trim list (Create list of Entries not on MAL)? [y/n] (Default: n): ", "n")

  if tempTrim.lower()[0] == "y":
    fTrim.trim_results(PROJECT_PATH, outputAnime.get('main'), outputManga.get('main'), False)
    if isSepNsfw:
      fTrim.trim_results(PROJECT_PATH, outputAnime.get('nsfw'), outputManga.get('nsfw'), True)

  # Get Entries not on Tachi
  tempTachi = fMain.inputX("Tachiyomi library json file (legacy backup): ", None)
  if tempTachi:
    fNotOnTachi.getNotOnTachi(outputManga.get('main'), tempTachi, False)
    if isSepNsfw:
      fNotOnTachi.getNotOnTachi(outputManga.get('nsfw'), tempTachi, True)

  fMain.inputX("Press <Enter> to exit..", "")
Esempio n. 6
0
def getMediaEntries(mediaType, paramvals):
    # Vars and Objects
    filepath = str(paramvals['root'])
    entryLog = str(paramvals['log'])
    accessToken = str(paramvals['access_tkn'])
    userID = int(paramvals['user_id'])
    username = str(paramvals['username'])
    useOAuth = bool(paramvals['use_auth'])
    isSepNsfw = bool(paramvals['sep_nsfw'])

    returnMedia = {}
    entryID = []  # List of IDs, to prevent duplicates
    jsonToDump = []  # List of Json dict object of results
    jsonToDumpNsfw = []  # List of Json dict object of results, 18+ entries
    isAdult = False  # Bool for 'isAdult' flag from Anilist
    nsfwToggle = 0  # 0=main, 1=nsfw. For arrays toggle
    source = "anilist_get" + mediaType
    fMain.logString("All vars are initiated", source)

    # Declare filepaths
    if mediaType == "ANIME":
        outputMedia = os.path.join(
            filepath, "output",
            "anime_" + datetime.now().strftime("%Y-%m-%d") + ".json")
        xmlMedia = os.path.join(
            filepath, "output",
            "anime_" + datetime.now().strftime("%Y-%m-%d") + ".xml")
        outputMedia18 = os.path.join(
            filepath, "output",
            "nsfw_anime_" + datetime.now().strftime("%Y-%m-%d") + ".json")
        xmlMedia18 = os.path.join(
            filepath, "output",
            "nsfw_anime_" + datetime.now().strftime("%Y-%m-%d") + ".xml")
    else:
        outputMedia = os.path.join(
            filepath, "output",
            "manga_" + datetime.now().strftime("%Y-%m-%d") + ".json")
        xmlMedia = os.path.join(
            filepath, "output",
            "manga_" + datetime.now().strftime("%Y-%m-%d") + ".xml")
        outputMedia18 = os.path.join(
            filepath, "output",
            "nsfw_manga_" + datetime.now().strftime("%Y-%m-%d") + ".json")
        xmlMedia18 = os.path.join(
            filepath, "output",
            "nsfw_manga_" + datetime.now().strftime("%Y-%m-%d") + ".xml")

    # Check if not existing
    if not (os.path.exists(outputMedia)):
        # Get JSON object
        if useOAuth:
            jsonMedia = fReq.anilist_userlist(accessToken, userID, mediaType)
        else:
            jsonMedia = fReq.anilist_userlist_public(userID, mediaType)

        # Check if not null
        if jsonMedia is not None:
            listMedia = jsonMedia["data"]["MediaListCollection"]["lists"]

            # Create vars
            # Count Manga entries
            cTotal = arr.array('i', [0, 0])
            cWatch = arr.array('i', [0, 0])
            cComplete = arr.array('i', [0, 0])
            cHold = arr.array('i', [0, 0])
            cDrop = arr.array('i', [0, 0])
            cPtw = arr.array('i', [0, 0])

            # Start generating JSON and XML..
            fMain.logString("Generating JSON and XML..", source)

            # Log duplicate entries
            fMain.logFile(entryLog, f'{mediaType} Entries')
            entryID.clear()  # Clear list

            # Iterate over the MediaCollection List
            for anime in listMedia:
                # Get entries
                animeInfo = anime["entries"]
                # Iterate over the anime information, inside the entries
                for entry in animeInfo:
                    # Get Anilist ID
                    anilistID = entry["media"]["id"]
                    # Get Anilist Status
                    AnilistStatus = fMain.validateStr(entry["status"])
                    # Get isAdult flag
                    isAdult = bool(entry["media"]["isAdult"])

                    # Check if already exists
                    if anilistID in entryID:
                        fMain.logFile(
                            entryLog,
                            f'Skipped: {str(anilistID)}, Duplicate {mediaType} entry.'
                        )
                        continue
                    else:
                        entryID.append(anilistID)

                    # Write to json file
                    if isAdult and isSepNsfw:
                        jsonToDumpNsfw.append(
                            fMain.entry_json(entry, mediaType))
                    else:
                        jsonToDump.append(fMain.entry_json(entry, mediaType))

                    # Write to MAL Xml File
                    malID = fMain.validateInt(entry["media"]["idMal"])
                    if malID != '0':
                        # Get XML strings
                        xmltoWrite = fMain.entry_xmlstr(
                            mediaType, malID, entry, str(AnilistStatus))
                        # Write to xml file
                        if isAdult and isSepNsfw:
                            nsfwToggle = 1
                            fMain.write_append(xmlMedia18, xmltoWrite)
                        else:
                            nsfwToggle = 0
                            fMain.write_append(xmlMedia, xmltoWrite)

                        # Add count
                        cTotal[nsfwToggle] += 1
                        if (AnilistStatus == "COMPLETED"):
                            cComplete[nsfwToggle] += 1
                        elif (AnilistStatus == "PAUSED"):
                            cHold[nsfwToggle] += 1
                        elif (AnilistStatus == "CURRENT"):
                            cWatch[nsfwToggle] += 1
                        elif (AnilistStatus == "DROPPED"):
                            cDrop[nsfwToggle] += 1
                        elif (AnilistStatus == "PLANNING"):
                            cPtw[nsfwToggle] += 1
                        elif (AnilistStatus == "REPEATING"):
                            cWatch[nsfwToggle] += 1

            # Dump JSON to file..
            if (fMain.dumpToJson(jsonToDump, outputMedia)):
                fMain.logString("Succesfully created json file!", source)
            else:
                fMain.logString("Error with creating json file!", source)
            fMain.logString(f"Done with {mediaType} JSON file..", source)

            # Dump JSON (nsfw) to file..
            if isSepNsfw:
                if (fMain.dumpToJson(jsonToDumpNsfw, outputMedia18)):
                    fMain.logString("Succesfully created json file!", source)
                else:
                    fMain.logString("Error with creating json file!", source)
                fMain.logString(f"Done with {mediaType} JSON file..", source)

            # Write to MAL xml file
            fMain.logString(f"Finalizing {mediaType} XML file..", source)
            malprepend = ""
            malprepend18 = ""

            mediastring = ""
            mediaexport = '0'
            mediawatchread = ""
            if mediaType == "ANIME":
                mediastring = "anime"
                mediaexport = '2'
                mediawatchread = "watch"
            else:
                mediastring = "manga"
                mediaexport = '1'
                mediawatchread = "read"

            fMain.write_append(xmlMedia, f'</my{mediastring}list>')
            if isSepNsfw:
                fMain.write_append(xmlMedia18, f'</my{mediastring}list>')
            # Total counts
            fMain.logString(f"Prepend 'myinfo' to {mediaType} XML file..",
                            source)
            malprepend = f'<?xml version="1.0" encoding="UTF-8" ?>\n<my{mediastring}list>\n'
            malprepend += '\t<myinfo>\n'
            malprepend += '\t\t' + fMain.toMalval('', 'user_id') + '\n'
            malprepend += '\t\t' + fMain.toMalval(username, 'user_name') + '\n'
            malprepend += '\t\t' + fMain.toMalval(mediaexport,
                                                  'user_export_type') + '\n'

            malprepend18 = malprepend  # Same prepend values as 'main'
            # Count for 'main'
            malprepend += '\t\t' + fMain.toMalval(str(
                cTotal[0]), f'user_total_{mediastring}') + '\n'
            malprepend += '\t\t' + fMain.toMalval(
                str(cWatch[0]), f'user_total_{mediawatchread}ing') + '\n'
            malprepend += '\t\t' + fMain.toMalval(str(
                cComplete[0]), 'user_total_completed') + '\n'
            malprepend += '\t\t' + fMain.toMalval(str(cHold[0]),
                                                  'user_total_onhold') + '\n'
            malprepend += '\t\t' + fMain.toMalval(str(cDrop[0]),
                                                  'user_total_dropped') + '\n'
            malprepend += '\t\t' + fMain.toMalval(
                str(cPtw[0]), f'user_total_planto{mediawatchread}') + '\n'
            # Count for 'nsfw'
            if isSepNsfw:
                malprepend18 += '\t\t' + fMain.toMalval(
                    str(cTotal[1]), f'user_total_{mediastring}') + '\n'
                malprepend18 += '\t\t' + fMain.toMalval(
                    str(cWatch[1]), f'user_total_{mediawatchread}ing') + '\n'
                malprepend18 += '\t\t' + fMain.toMalval(
                    str(cComplete[1]), 'user_total_completed') + '\n'
                malprepend18 += '\t\t' + fMain.toMalval(
                    str(cHold[1]), 'user_total_onhold') + '\n'
                malprepend18 += '\t\t' + fMain.toMalval(
                    str(cDrop[1]), 'user_total_dropped') + '\n'
                malprepend18 += '\t\t' + fMain.toMalval(
                    str(cPtw[1]), f'user_total_planto{mediawatchread}') + '\n'

            malprepend += '\t</myinfo>\n'
            malprepend18 += '\t</myinfo>\n'

            fMain.line_prepender(xmlMedia, malprepend)
            if isSepNsfw:
                fMain.line_prepender(xmlMedia18, malprepend18)
            fMain.logString(f"Done with {mediaType} XML file..", source)

            # Done anime/manga
            fMain.logString("Done! File generated: " + outputMedia, source)
            fMain.logString("Done! File generated: " + xmlMedia, source)
            if isSepNsfw:
                fMain.logString("Done! File generated: " + outputMedia18,
                                source)
                fMain.logString("Done! File generated: " + xmlMedia18, source)

    # Already existing!
    else:
        fMain.logString(f"{mediaType} file already exist!: " + outputMedia,
                        source)

    returnMedia = {'main': outputMedia, 'nsfw': outputMedia18}
    return returnMedia
Esempio n. 7
0
# Imports
import os
from datetime import datetime
import array as arr
# Local Imports
import func.main as fMain
import func.anilist_request as fReq

fMain.logString("Imported func.anilist_getMedia", "")


# Main Function
def getMediaEntries(mediaType, paramvals):
    # Vars and Objects
    filepath = str(paramvals['root'])
    entryLog = str(paramvals['log'])
    accessToken = str(paramvals['access_tkn'])
    userID = int(paramvals['user_id'])
    username = str(paramvals['username'])
    useOAuth = bool(paramvals['use_auth'])
    isSepNsfw = bool(paramvals['sep_nsfw'])

    returnMedia = {}
    entryID = []  # List of IDs, to prevent duplicates
    jsonToDump = []  # List of Json dict object of results
    jsonToDumpNsfw = []  # List of Json dict object of results, 18+ entries
    isAdult = False  # Bool for 'isAdult' flag from Anilist
    nsfwToggle = 0  # 0=main, 1=nsfw. For arrays toggle
    source = "anilist_get" + mediaType
    fMain.logString("All vars are initiated", source)