Compare commits
11 Commits
fd264a9f70
...
7d1941ed75
Author | SHA1 | Date |
---|---|---|
CommanderRedYT | 7d1941ed75 | |
CommanderRedYT | 429010f664 | |
CommanderRedYT | 61b584f547 | |
CommanderRedYT | 5833594769 | |
CommanderRedYT | a17d8de8d4 | |
CommanderRedYT | 1ea8832cac | |
CommanderRedYT | 8b70df5f93 | |
CommanderRedYT | fccf9c865a | |
CommanderRedYT | a4b5081c7a | |
CommanderRedYT | 2481248736 | |
Simon | eb4558569c |
36
README.md
36
README.md
|
@ -53,6 +53,7 @@ An example configuration is provided in the docker-compose.yml file. Configure t
|
|||
- `TA_TOKEN`: Tube Archivist API token, accessible from the settings page
|
||||
- `JF_URL`: Full URL where Jellyfin is reachable
|
||||
- `JF_TOKEN`: Jellyfin API token
|
||||
- `JF_FOLDER`: Folder override if your folder is not named "YouTube" on your Filesystem.
|
||||
- `LISTEN_PORT`: Optionally change the port where the integration is listening for messages. Defaults to `8001`. If you change this, make sure to also change the json link for auto trigger as described below.
|
||||
|
||||
Mount the `/youtube` folder from Tube Archivist also in this container at `/youtube` to give this integration access to the media archive.
|
||||
|
@ -83,6 +84,7 @@ pip install requests
|
|||
- `ta_token`: Tube Archivist API token, accessible from the settings page
|
||||
- `jf_url`: Full URL where Jellyfin is reachable
|
||||
- `jf_token`: Jellyfin API token
|
||||
- `jf_folder`: Name of the folder where TubeArchivist puts the files into
|
||||
|
||||
Then run the script from the main folder with python, e.g.
|
||||
```python
|
||||
|
@ -98,37 +100,3 @@ Some ideas for why that is:
|
|||
- Your JF busy, too slow or is already refreshing another library and is not picking up the folder in time.
|
||||
- JF doesn't have the permissions to see the folder created by the extension.
|
||||
- You didn't mount the volumes as expected and JF is looking in the wrong place.
|
||||
|
||||
## Migration problems
|
||||
Due to the filesystem change between Tube Archivist v0.3.6 to v0.4.0, this will reset your YouTube videos in Jellyfin and will add them as new again. Unfortunately there is no migration path.
|
||||
|
||||
To import an existing Tube Archivist archive created with v0.3.4 or before, there are a few manual steps needed. These issues are fixed with videos and channels indexed with v0.3.5 and later.
|
||||
|
||||
Apply these fixes *before* importing the archive.
|
||||
|
||||
**Permissions**
|
||||
Fix folder permissions not owned by the correct user. Navigate to the `ta_video_path` and run:
|
||||
|
||||
```bash
|
||||
sudo chown -R $UID:$GID .
|
||||
```
|
||||
|
||||
|
||||
**Channel Art**
|
||||
Tube Archivist v0.3.5 adds additional art work to the channel metadata. To trigger an automatic refresh of your old channels open a Python shell within the *tubearchivist* container:
|
||||
|
||||
```bash
|
||||
docker exec -it tubearchivist python
|
||||
```
|
||||
|
||||
Then execute these lines to trigger a background task for a full metadata refresh for all channels.
|
||||
|
||||
```python
|
||||
from home.src.es.connect import IndexPaginate
|
||||
from home.tasks import check_reindex
|
||||
|
||||
query = {"query": {"match_all": {}}}
|
||||
all_channels = IndexPaginate("ta_channel", query).get_results()
|
||||
reindex = {"channel": [i["channel_id"] for i in all_channels]}
|
||||
check_reindex.delay(data=reindex)
|
||||
```
|
||||
|
|
|
@ -38,6 +38,7 @@ def get_config_env() -> ConfigType | Literal[False]:
|
|||
"ta_token": os.environ["TA_TOKEN"],
|
||||
"jf_url": os.environ["JF_URL"],
|
||||
"jf_token": os.environ["JF_TOKEN"],
|
||||
"jf_folder": os.environ.get("JF_FOLDER", "youtube"),
|
||||
}
|
||||
return config_content
|
||||
|
||||
|
|
|
@ -9,7 +9,14 @@ from src.static_types import ConfigType, TAChannel, TAVideo
|
|||
|
||||
CONFIG: ConfigType = get_config()
|
||||
TIMEOUT = 60
|
||||
EXPECTED_ENV = {"ta_url", "ta_token", "jf_url", "jf_token", "ta_video_path"}
|
||||
EXPECTED_ENV = {
|
||||
"ta_url",
|
||||
"ta_token",
|
||||
"jf_url",
|
||||
"jf_token",
|
||||
"ta_video_path",
|
||||
"jf_folder",
|
||||
}
|
||||
|
||||
|
||||
class Jellyfin:
|
||||
|
|
|
@ -22,8 +22,10 @@ class Library:
|
|||
"""get collection id for youtube folder"""
|
||||
path: str = "Items?Recursive=true&includeItemTypes=Folder"
|
||||
folders: dict = Jellyfin().get(path)
|
||||
folder_name: str = get_config()["jf_folder"]
|
||||
|
||||
for folder in folders["Items"]:
|
||||
if folder.get("Name").lower() == "youtube":
|
||||
if folder.get("Name").lower() == folder_name.lower():
|
||||
return folder.get("Id")
|
||||
|
||||
raise ValueError("youtube folder not found")
|
||||
|
@ -72,7 +74,7 @@ class Library:
|
|||
path: str = f"Items/{collection_id}/Refresh?Recursive=true&ImageRefreshMode=Default&MetadataRefreshMode=Default" # noqa: E501
|
||||
Jellyfin().post(path, False)
|
||||
|
||||
for _ in range(12):
|
||||
for _ in range(24):
|
||||
response = Jellyfin().get("Library/VirtualFolders")
|
||||
for folder in response:
|
||||
if not folder["ItemId"] == collection_id:
|
||||
|
@ -82,7 +84,7 @@ class Library:
|
|||
return
|
||||
|
||||
print("waiting for library refresh")
|
||||
sleep(5)
|
||||
sleep(10)
|
||||
|
||||
|
||||
class Show:
|
||||
|
@ -207,10 +209,13 @@ class Show:
|
|||
"""wait for season to be created in JF"""
|
||||
jf_id: str = self.show["Id"]
|
||||
path: str = f"Items/{jf_id}/Refresh?Recursive=true&ImageRefreshMode=Default&MetadataRefreshMode=Default" # noqa: E501
|
||||
print(f"[setup] {path=}")
|
||||
Jellyfin().post(path, False)
|
||||
for _ in range(12):
|
||||
for _ in range(100):
|
||||
all_existing: set[str] = set(self._get_existing_seasons())
|
||||
|
||||
print(f"[setup] seasons: {all_existing} {expected_season=}")
|
||||
|
||||
if expected_season in all_existing:
|
||||
return
|
||||
|
||||
|
@ -225,7 +230,11 @@ class Show:
|
|||
path: str = f"Shows/{series_id}/Seasons"
|
||||
all_seasons: dict = Jellyfin().get(path)
|
||||
|
||||
return [str(i.get("IndexNumber")) for i in all_seasons["Items"]]
|
||||
print(f"[setup] {path=} all_seasons_items={all_seasons['Items']}")
|
||||
|
||||
res = [str(i.get("Name")) for i in all_seasons["Items"]]
|
||||
|
||||
return [name.split(' ')[1] if ' ' in name else name for name in res]
|
||||
|
||||
def delete_folders(self, folders: list[str]) -> None:
|
||||
"""delete temporary folders created"""
|
||||
|
|
|
@ -11,6 +11,7 @@ class ConfigType(TypedDict):
|
|||
ta_token: str
|
||||
jf_url: str
|
||||
jf_token: str
|
||||
jf_folder: str
|
||||
|
||||
|
||||
class TAChannel(TypedDict):
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
"ta_url": "http://tubearchivist.local",
|
||||
"ta_token": "xxxxxxxxxxxxxxxx",
|
||||
"jf_url": "http://jellyfin.local:8096",
|
||||
"jf_token": "yyyyyyyyyyyyyyyy"
|
||||
"jf_token": "yyyyyyyyyyyyyyyy",
|
||||
"jf_folder": "YouTube"
|
||||
}
|
||||
|
|
|
@ -17,12 +17,12 @@ function validate {
|
|||
echo "running black"
|
||||
black --force-exclude "migrations/*" --diff --color --check -l 79 "$check_path"
|
||||
echo "running codespell"
|
||||
codespell --skip="./.git,./.venv,./.mypy_cache" "$check_path"
|
||||
codespell --skip="./.git,./.venv,venv,./.mypy_cache" "$check_path"
|
||||
echo "running flake8"
|
||||
flake8 "$check_path" --exclude "migrations,.venv" --count --max-complexity=10 \
|
||||
flake8 "$check_path" --exclude "migrations,.venv,venv" --count --max-complexity=10 \
|
||||
--max-line-length=79 --show-source --statistics
|
||||
echo "running isort"
|
||||
isort --skip "migrations" --skip ".venv" --check-only --diff --profile black -l 79 "$check_path"
|
||||
isort --skip "migrations" --skip ".venv" --skip "venv" --check-only --diff --profile black -l 79 "$check_path"
|
||||
printf " \n> all validations passed\n"
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue