Skip to content

Commit

Permalink
feat: download specific character cutin/l2d/summon animation
Browse files Browse the repository at this point in the history
  • Loading branch information
MightyZanark committed Jan 4, 2024
1 parent 3c9064f commit 7b211b4
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 48 deletions.
4 changes: 2 additions & 2 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"TruthVersion": 10052700,
"hash": "a306a3bb8a953a394055248e0253b3e6",
"TruthVersion": 10052800,
"hash": "4aff7e78b0180b97790c81682f3215c8",
"assetmanifest": "http://prd-priconne-redive.akamaized.net/dl/Resources/version/Jpn/AssetBundles/Windows/manifest/manifest_assetmanifest",
"masterdata": "http://prd-priconne-redive.akamaized.net/dl/Resources/version/Jpn/AssetBundles/Windows/manifest/masterdata_assetmanifest",
"movie": "http://prd-priconne-redive.akamaized.net/dl/Resources/version/Jpn/Movie/PC/High/manifest/moviemanifest",
Expand Down
154 changes: 111 additions & 43 deletions scripts/Movie.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import os
import re
import sqlite3
import traceback
import subprocess
import multiprocessing
from concurrent.futures import ThreadPoolExecutor

import requests
import PyCriCodecs as pcc
from tqdm import tqdm

import Constants

Expand All @@ -17,23 +19,35 @@ def generate_list(mov_name: str, dir_name: str) -> tuple[list[str], list[str]]:
"""

# print(f'mov_name: {mov_name} | dir_name: {dir_name} | isdir: {os.path.isdir(dir_name)}')
if not os.path.isdir(dir_name):
os.makedirs(dir_name)

# print(mov_name)
name = []
hash = []
names = []
hashes = []
with open(Constants.MOVIEMANIFEST, "r") as m:
for lines in m:
l = lines.split(",")
n = l[0].split("/")[-1]
h = l[1]

if re.fullmatch(mov_name, n):
name.append(os.path.join(dir_name, n))
hash.append(h)
names.append(os.path.join(dir_name, n))
hashes.append(h)

return name, hash
return names, hashes


def get_filename_and_hash(mov_name: re.Pattern, id: str) -> tuple[str] | bool:
"""Gets the filename and hash for a specific unit id"""

with open(Constants.MOVIEMANIFEST, "r") as m:
for lines in m:
l = lines.split(",")
name = l[0].split("/")[-1]
hash = l[1]

if re.fullmatch(mov_name, name) and id in name:
return name, hash

return False


def download_file(name: str, hash: str) -> None:
Expand Down Expand Up @@ -146,9 +160,9 @@ def extract(filename: str, dirname: str = "") -> list[str]:
out.write(data)

elif "SFA" in k:
audio = pcc.ADX(data)
audio = pcc.ADX.decode(data)
with open(filenames[i+1], "wb") as out:
out.write(audio.decode())
out.write(audio)

else:
raise NotImplementedError(f'Unknown type of data: {k}\nHeader: {data[:4]}')
Expand All @@ -163,6 +177,20 @@ def extract(filename: str, dirname: str = "") -> list[str]:
return filenames


def download_all(mov_name: str, dir_name: str) -> None:
"""Downloads all the usm of a movie type and converts them to mp4"""

names, hashes = generate_list(mov_name, dir_name)

with ThreadPoolExecutor() as thread:
thread.map(download_file, names, hashes)
thread.shutdown(wait=True)

with multiprocessing.Pool() as pool:
pool.map(convert_file, names)
pool.terminate()


def movie() -> None:
"""
Runs the Movie download and conversion logic
Expand All @@ -177,41 +205,81 @@ def movie() -> None:
input("Press ENTER to continue")
return

else:
print("Select type: (write the number)")
print("1. cutin\n2. l2d\n3. summon\n4. event")
mov_type = input(">> ").lower().strip()

try:
mov_dict = {"1": "cutin", "2": "l2d", "3": "summon", "4": "event"}
mov_type = mov_dict[mov_type]
dir_name = Constants.MOVIE_TYPES["dir"][mov_type]
mov_name = Constants.MOVIE_TYPES["name"][mov_type]
name, hash = generate_list(mov_name, dir_name)

except KeyError:
print("> INVALID TYPE! <")
print("Current types are only 'cutin', 'l2d', 'summon', or 'event'\n")
input("Press ENTER to continue")
return
print("Select type: (write the number)")
print("1. cutin\n2. l2d\n3. summon\n4. event")
mov_type = input(">> ").lower().strip()

try:
mov_dict = {"1": "cutin", "2": "l2d", "3": "summon", "4": "event"}
mov_type = mov_dict[mov_type]
dir_name = Constants.MOVIE_TYPES["dir"][mov_type]
mov_name = Constants.MOVIE_TYPES["name"][mov_type]

except KeyError:
print("> INVALID TYPE! <")
print("Current types are only 'cutin' (1), 'l2d' (2), 'summon' (3), or 'event' (4)\n")
input("Press ENTER to continue")
return

if not os.path.isdir(dir_name):
os.makedirs(dir_name)

if mov_type == 'event':
download_all(mov_name, dir_name)

else:
select = input(f"Download all {mov_type}? (y/N, default: N)\n").strip().lower()

if select and (select == 'y' or select[0] == 'y'):
download_all(mov_name, dir_name)

else:
# ThreadPoolExecutor and multiprocessing makes it so the
# downloading and converting of a file doesn't happen 1 by 1
# Instead, a few files are downloaded at a time and after all
# of those files finished downloading, they get converted a
# few files at the same time as well
# The number of files downloaded or converted at a time will
# depend on your system and download speed (for download)
with ThreadPoolExecutor() as thread:
thread.map(download_file, name, hash)
thread.shutdown(wait=True)

with multiprocessing.Pool() as pool:
pool.map(convert_file, name)
pool.terminate()

input(">> Download and conversion completed!\nPress ENTER to continue")
con = sqlite3.connect(os.path.join(Constants.DB_DIR, 'master.db'))
cur = con.cursor()
query = cur.execute(
"SELECT unit_name, unit_id "
"FROM unit_data "
"WHERE unit_id < 190000 AND move_speed = 450 AND unit_id != 170101"
).fetchall()
names = [q[0].strip() for q in query]
ids = [q[1] for q in query]
name_lst = ''
for idx, name in enumerate(names, 1):
offset = 15 - len(name)
name += u'\u3000' * offset
idx_str = str(idx) + "."
name_lst += f"{idx_str:<4} {name}"
print(f"{idx_str:<4} {name}", end='')
if idx % 3 == 0:
name_lst += '\n'
print()
print()

correct = False
while not correct:
chara = input("Enter the character number: ").strip()
names_len = len(names)
while not chara.isdigit() or int(chara) < 1 or int(chara) > names_len:
chara = input(f"Invalid number! Please enter a number between 1-{names_len}: ")

chara = int(chara)-1
name = names[chara]
id = ids[chara]

correct = input(f"Is {name} the right character? (y/N, default: y)\n").strip()
correct = True if correct != 'n' or correct[0] != 'n' else False

found = get_filename_and_hash(mov_name, str(id)[:-2])
if not found:
print(f"{name} does not have a {mov_type}")

else:
name, hash = found
name = os.path.join(dir_name, name)
download_file(name, hash)
convert_file(name)

input(">> Download and conversion completed!\nPress ENTER to continue")


if __name__ == "__main__":
Expand Down
6 changes: 3 additions & 3 deletions scripts/Run.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import sys
import multiprocessing
from .DBCheck import update_db
from .Movie import movie
from .Sound import sound
from DBCheck import update_db
from Movie import movie
from Sound import sound

def run_main():
print("\n---------- Priconne Utilities ----------\n")
Expand Down

0 comments on commit 7b211b4

Please sign in to comment.