Skip to content

Commit

Permalink
Implement the sync script and add an e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
jordansimsmith committed Oct 28, 2024
1 parent b4cdc48 commit b33bc62
Show file tree
Hide file tree
Showing 13 changed files with 344 additions and 38 deletions.
13 changes: 11 additions & 2 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,23 @@ oci.pull(
],
tag = "2.5.2",
)
oci.pull(
name = "alpine",
image = "docker.io/library/alpine",
platforms = [
"linux/amd64",
"linux/arm64/v8",
],
tag = "3.17",
)
oci.pull(
name = "ryuk",
image = "docker.io/testcontainers/ryuk",
platforms = [
"linux/amd64",
"linux/arm64",
],
tag = "0.6.0",
tag = "0.7.0",
)
oci.pull(
name = "localstack",
Expand All @@ -78,7 +87,7 @@ oci.pull(
],
tag = "3.8.0",
)
use_repo(oci, "dynamodb", "dynamodb_linux_amd64", "dynamodb_linux_arm64", "localstack", "localstack_linux_amd64", "localstack_linux_arm64", "ryuk", "ryuk_linux_amd64", "ryuk_linux_arm64")
use_repo(oci, "alpine", "alpine_linux_amd64", "alpine_linux_arm64_v8", "dynamodb", "dynamodb_linux_amd64", "dynamodb_linux_arm64", "localstack", "localstack_linux_amd64", "localstack_linux_arm64", "ryuk", "ryuk_linux_amd64", "ryuk_linux_arm64")

bazel_dep(name = "aspect_rules_lint", version = "1.0.0-rc8")

Expand Down
54 changes: 50 additions & 4 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion immersion_tracker_api/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ oci_image(
base = "@localstack//:localstack",
env = {
"LOCALSTACK_LAMBDA_IGNORE_ARCHITECTURE": 1,
"LOCALSTACK_LAMBDA_KEEPALIVE_MS": 0,
},
tars = [
":local-init-resources.tar",
Expand Down Expand Up @@ -260,16 +261,28 @@ java_test_suite(
data = [
":sync-episodes-script.py",
],
resources = ["src/test/resources/test.properties"],
env = {
"IMMERSION_TRACKER_USER": "alice",
"IMMERSION_TRACKER_PASSWORD": "password",
"TVDB_API_KEY": "",
},
resources = [
"src/test/resources/logback-test.xml",
"src/test/resources/test.properties",
],
runner = "junit5",
tags = ["manual"],
test_suffixes = ["E2ETest.java"],
runtime_deps = JUNIT5_DEPS,
deps = [
":lib",
":test-lib",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:ch_qos_logback_logback_core",
"@maven//:com_google_guava_guava",
"@maven//:org_assertj_assertj_core",
"@maven//:org_junit_jupiter_junit_jupiter_api",
"@maven//:org_slf4j_slf4j_api",
"@maven//:org_testcontainers_junit_jupiter",
],
)
10 changes: 5 additions & 5 deletions immersion_tracker_api/local/init_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
)

secretsmanager_client.create_secret(
Name="immersion_tracker",
Name="immersion_tracker_api",
SecretString=json.dumps(
{"users": [], "tvdb_api_key": os.getenv("TVDB_API_KEY", "")}
),
Expand Down Expand Up @@ -74,28 +74,28 @@

configs = [
{
"function_name": "immersion_tracker_get_progress_handler",
"function_name": "get_progress_handler",
"resource_path_part": "progress",
"http_method": "GET",
"handler_name": "com.jordansimsmith.immersiontracker.GetProgressHandler",
"zip_file": "get-progress-handler_deploy.jar",
},
{
"function_name": "immersion_tracker_get_shows_handler",
"function_name": "get_shows_handler",
"resource_path_part": "shows",
"http_method": "GET",
"handler_name": "com.jordansimsmith.immersiontracker.GetShowsHandler",
"zip_file": "get-shows-handler_deploy.jar",
},
{
"function_name": "immersion_tracker_update_show_handler",
"function_name": "update_show_handler",
"resource_path_part": "show",
"http_method": "PUT",
"handler_name": "com.jordansimsmith.immersiontracker.UpdateShowHandler",
"zip_file": "update-show-handler_deploy.jar",
},
{
"function_name": "immersion_tracker_sync_episodes_handler",
"function_name": "sync_episodes_handler",
"resource_path_part": "sync",
"http_method": "POST",
"handler_name": "com.jordansimsmith.immersiontracker.SyncEpisodesHandler",
Expand Down
126 changes: 120 additions & 6 deletions immersion_tracker_api/script/sync_episodes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,121 @@
import time
import os
import requests
import json
import urllib.parse

print("Hello, world!")
time.sleep(1)
n = input("Pick a number:\n")
time.sleep(1)
print("You picked " + n)

def main():
local_episodes_watched = find_local_episodes_watched()
if not len(local_episodes_watched):
print("No local episodes watched, exiting...")
return

sync_local_episodes_watched(local_episodes_watched)
update_remote_shows()
get_remote_show_progress()

print()
input("Press ENTER to close...")


def find_local_episodes_watched():
print("Finding local episodes watched...")
episodes = []

for show in os.listdir(os.path.curdir):
if not os.path.isdir(show):
continue

watched = os.path.join(show, "watched")
if not os.path.isdir(watched):
continue

for episode in os.listdir(watched):
if not os.path.isfile(os.path.join(watched, episode)):
continue

episode = {"folder_name": show, "file_name": os.path.basename(episode)}
episodes.append(episode)

return episodes


def sync_local_episodes_watched(episodes):
print(f"Syncing {len(episodes)} local episodes watched...")

res = send_request("POST", "sync", {"episodes": episodes})
episodes_added = res["episodes_added"]
print(f"Successfully added {episodes_added} new episodes to the remote server.")


def update_remote_shows():
print("Retrieving remote show metadata...")

res = send_request("GET", "shows")
for show in res["shows"]:
if show["tvdb_id"]:
continue

folder_name = show["folder_name"]
tvdb_id = int(input(f"Enter the TVDB id for show {folder_name}:\n"))
send_request("PUT", "show", {"folder_name": folder_name, "tvdb_id": tvdb_id})
print("Successfully updated show metadata.")


def get_remote_show_progress():
print("Retrieving progress summary...")
print()

res = send_request("GET", "progress")
for show in res["shows"]:
name = show["name"] or "Unknown"
episodes_watched = show["episodes_watched"]
print(f"{episodes_watched} episodes of {name}.")

episodes_watched_today = res["episodes_watched_today"]
total_hours_watched = res["total_hours_watched"]

print()
print(f"{episodes_watched_today} episodes watched today.")
print(f"{total_hours_watched} total hours watched.")


def send_request(method, path, body=None):
user = os.getenv("IMMERSION_TRACKER_USER")
if not user:
raise Exception("IMMERSION_TRACKER_USER is not set.")

password = os.getenv("IMMERSION_TRACKER_PASSWORD")
if not password:
raise Exception("IMMERSION_TRACKER_PASSWORD is not set.")

base_path = (
os.getenv("IMMERSION_TRACKER_API_URL")
or "https://9tpnqbuz76.execute-api.ap-southeast-2.amazonaws.com/prod"
)
if base_path[-1] != "/":
base_path += "/"
if path[0] == "/":
path = path[1:]
url = urllib.parse.urljoin(base_path, path)

headers = {
"Content-Type": "application/json;charset=UTF-8",
"Accept": "application/json;charset=UTF-8",
}
params = {"user": user}
data = json.dumps(body).encode("utf-8") if body else None

res = requests.request(
method, url, data=data, params=params, headers=headers, auth=(user, password)
)
if res.status_code != 200:
raise Exception(
f"{method} {path} request failed with non code {res.status_code} and body {res.text}"
)

return res.json()


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jordansimsmith.immersiontracker;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
Expand All @@ -26,14 +27,18 @@ public HttpTvdbClient(ObjectMapper objectMapper, Secrets secrets, HttpClient htt

private record LoginRequest(@JsonProperty("apikey") String apiKey) {}

@JsonIgnoreProperties(ignoreUnknown = true)
private record LoginResponse(
@JsonProperty("status") String status, @JsonProperty("data") LoginData data) {}

@JsonIgnoreProperties(ignoreUnknown = true)
private record LoginData(@JsonProperty("token") String token) {}

@JsonIgnoreProperties(ignoreUnknown = true)
private record SeriesResponse(
@JsonProperty("status") String status, @JsonProperty("data") SeriesData data) {}

@JsonIgnoreProperties(ignoreUnknown = true)
private record SeriesData(@JsonProperty("name") String name, @JsonProperty String image) {}

@Override
Expand Down Expand Up @@ -79,6 +84,7 @@ private Show doGetShow(int id) throws Exception {
.uri(new URI("https://api4.thetvdb.com/v4/series/" + id))
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + token)
.GET()
.build();
var seriesRes = httpClient.send(seriesReq, HttpResponse.BodyHandlers.ofString());
Expand Down
Loading

0 comments on commit b33bc62

Please sign in to comment.