Skip to content

Commit

Permalink
Bugfix: Empty Sony 360 Reality Audio Files (#33)
Browse files Browse the repository at this point in the history
* Fix errors arisen from 'flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics'

* Clean up based on flake8 suggestions

* Make some mypy-inspired changes

* Fix empty files with Sony 360 Reality Audio codec

* Update docker-image.yml to only build on releases

* Edit docker-image.yml, following https://docs.github.com/en/actions/
  • Loading branch information
ebb-earl-co authored Jan 6, 2024
1 parent 37e7578 commit 55a4ee6
Show file tree
Hide file tree
Showing 18 changed files with 363 additions and 296 deletions.
44 changes: 36 additions & 8 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,46 @@
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
name: Docker Image CI

on:
release:
types: ["published"]
push:
branches: [ "trunk" ]
pull_request:
branches: [ "trunk" ]
branches: ["trunk"]

jobs:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

build:

jobs:
build:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: docker build . --file Dockerfile --tag ghcr.io/ebb-earl-co/tidal-wave:trunk
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
3 changes: 3 additions & 0 deletions pyinstall.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from tidal_wave.main import app

app()
18 changes: 17 additions & 1 deletion release_artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
VERSION="${1:-latest}"

command -v python3 >/dev/null 2>&1 || { echo >&2 "I require Python3 but it's not installed. Aborting."; exit 1; }
PY3VERSION="$(command -v python3)" -c "import sys;print('.'.join(map(str, sys.version_info[:2])))"

if ! command -v cargo &> /dev/null;
then
Expand All @@ -11,10 +12,25 @@ fi
/usr/bin/env python3 -m venv ./venv && \
source ./venv/bin/activate && \
python3 -m pip install --upgrade pip setuptools wheel && \
python3 -m pip install build shiv twine && \
python3 -m pip install -r requirements.txt && \
python3 -m pip install build pyinstaller shiv twine && \
python3 -m shiv --compressed --reproducible -c tidal-wave -o ~/tools/tidal-wave_${VERSION}.pyz . && \ # shiv executable
PYAPP_PROJECT_NAME=tidal-wave PYAPP_PROJECT_VERSION=${VERSION} cargo install pyapp --root out && \
mv out/bin/pyapp ~/tools/tidal-wave_${VERSION}.pyapp && \
PYAPP_PROJECT_NAME=tidal-wave PYAPP_PROJECT_VERSION=${VERSION} PYAPP_FULL_ISOLATION=1 PYAPP_DISTRIBUTION_EMBED=1 PYAPP_PYTHON_VERSION=3.11 cargo install pyapp --root out && \
mv out/bin/pyapp ~/tools/tidal-wave_${VERSION}_py311.pyapp && \
rm -r out/

# Pyinstaller
# TODO: figure out how to bundle FFmpeg legally;
# i.e., what are the License ramifications for this project
python3 -m pyinstaller \
--distpath ./.dist/ \
--workpath ./.build/ \
--onefile \
--name tidal-wave_${VERSION}
--paths tidal_wave \
--paths ./venv/lib/python${PY3VERSION}/site-packages/ \
# --add-data "./ffmpeg/*:./ffmpeg/" \
./pyinstall.py && \
rm -r ./.dist/ ./.build/
8 changes: 5 additions & 3 deletions tidal_wave/album.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
from requests import Session

from .media import AudioFormat
from .models import AlbumsEndpointResponseJSON
from .models import (
AlbumsEndpointResponseJSON,
AlbumsItemsResponseJSON,
AlbumsReviewResponseJSON,
)
from .requesting import request_albums, request_album_items, request_album_review
from .track import Track
from .utils import download_cover_image
Expand All @@ -34,8 +38,6 @@ def get_metadata(self, session: Session):
)

def get_review(self, session: Session):
if self.album_dir is None:
self.set_dir(out_dir=out_dir)
self.album_review: Optional[AlbumsReviewResponseJSON] = request_album_review(
session=session, identifier=self.album_id
)
Expand Down
26 changes: 13 additions & 13 deletions tidal_wave/artist.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
from dataclasses import dataclass, field
import json
from dataclasses import dataclass
import logging
from pathlib import Path
import shutil
import sys
from types import SimpleNamespace
from typing import Dict, List, Optional, Tuple, Union
from typing import List, Optional

from requests import HTTPError, Session
from requests import Session

from .album import Album
from .media import AudioFormat
from .models import (
ArtistsAlbumsResponseJSON,
ArtistsEndpointResponseJSON,
ArtistsVideosResponseJSON,
)
from .requesting import (
request_artists,
request_artists_albums,
request_artists_audio_works,
request_artists_videos,
)
from .track import Track
from .utils import download_cover_image, TIDAL_API_URL
from .utils import download_cover_image
from .video import Video

logger = logging.getLogger("__name__")
Expand All @@ -32,7 +32,7 @@ def set_metadata(self, session: Session):
"""This function requests from TIDAL API endpoint /artists and
stores the results in self.metadata"""
self.metadata: Optional[ArtistsEndpointResponseJSON] = request_artists(
session=session, identifier=self.artist_id
session, self.artist_id
)

def save_artist_image(self, session: Session):
Expand All @@ -46,21 +46,21 @@ def set_albums(self, session: Session):
"""This function requests from TIDAL API endpoint /artists/albums and
stores the results in self.albums"""
self.albums: Optional[ArtistsAlbumsResponseJSON] = request_artists_albums(
session=session, identifier=self.artist_id
session, self.artist_id
)

def set_audio_works(self, session: Session):
"""This function requests from TIDAL API endpoint
/artists/albums?filter=EPSANDSINGLES and stores the results in self.albums"""
self.albums: Optional[ArtistsAlbumsResponseJSON] = request_artists_audio_works(
session=session, identifier=self.artist_id
session, self.artist_id
)

def set_videos(self, session: Session):
"""This function requests from TIDAL API endpoint /artists/videos and
stores the results in self.albums"""
self.videos: Optional[ArtistsVideosResponseJSON] = request_artists_videos(
session=session, identifier=self.artist_id
session, self.artist_id
)

def set_dir(self, out_dir: Path):
Expand Down
5 changes: 1 addition & 4 deletions tidal_wave/dash.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
#!/usr/bin/env python3
#! -*- coding: utf-8 -*-

from dataclasses import dataclass, field
import json
import re
from typing import Literal, List, Optional, Tuple, Union
from typing import List, Optional, Tuple, Union
from xml.etree import ElementTree as ET

import dataclass_wizard
Expand Down
8 changes: 5 additions & 3 deletions tidal_wave/hls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json
import logging
from requests import Response, Session
from typing import List, Optional, Union
from requests import Session
from typing import Dict, List, Optional, Union

from .models import VideosEndpointStreamResponseJSON

Expand Down Expand Up @@ -29,7 +29,9 @@ def download(
return response.text, response.url


def playlister(session: Session, vesrj: VideosEndpointStreamResponseJSON) -> m3u8.M3U8:
def playlister(
session: Session, vesrj: Optional[VideosEndpointStreamResponseJSON]
) -> m3u8.M3U8:
"""Attempts to parse a VideosEndpointStreamResponseJSON object into an
m3u8.M3U8 object. Requires fetching HTTP(s) resources, so takes a
requests.Session object as an argument. If error occurs, raises
Expand Down
5 changes: 1 addition & 4 deletions tidal_wave/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ def load_token_from_disk(
try:
bearer_token_json: dict = json.loads(decoded_token_file_contents)
except json.decoder.JSONDecodeError:
logger.warning(
f"File '{path_to_token_file.absolute()}' cannot be parsed as JSON"
)
logger.warning(f"File '{token_path.absolute()}' cannot be parsed as JSON")
return
else:
return bearer_token_json.get("access_token")
Expand Down Expand Up @@ -199,7 +197,6 @@ def login_windows(
logger.critical("Access token is not valid: exiting now.")
else:
logger.debug(f"Writing this access token to '{str(token_path.absolute())}'")
# s.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) TIDAL/2.35.0 Chrome/108.0.5359.215 Electron/22.3.27 Safari/537.36"
s.headers["User-Agent"] = "TIDAL_NATIVE_PLAYER/WIN/3.1.2.195"
s.params["deviceType"] = "DESKTOP"
to_write: dict = {
Expand Down
7 changes: 1 addition & 6 deletions tidal_wave/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
#!/usr/bin/env python3
#! -*- coding: utf-8 -*-

from contextlib import closing
import logging
from pathlib import Path
import sys
from typing import Optional
from typing import Optional, Union

from .login import login, AudioFormat, LogLevel
from .album import Album
Expand All @@ -23,7 +19,6 @@
TidalTrack,
TidalVideo,
)
from .requesting import get_album_id

from platformdirs import user_music_path
import typer
Expand Down
4 changes: 1 addition & 3 deletions tidal_wave/media.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from enum import Enum
import random
import time
from typing import Dict, Optional
from typing import Dict


class AudioFormat(str, Enum):
Expand Down
14 changes: 9 additions & 5 deletions tidal_wave/mix.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
from dataclasses import dataclass, field
from dataclasses import dataclass
import json
import logging
from pathlib import Path
import shutil
import sys
from types import SimpleNamespace
from typing import Dict, List, Optional, Tuple, Union
from typing import Dict, List, Optional, Set, Tuple, Union

from requests import HTTPError, Session

from .media import AudioFormat
from .models import TracksEndpointResponseJSON, VideosEndpointResponseJSON
from .models import (
PlaylistsEndpointResponseJSON,
TracksEndpointResponseJSON,
VideosEndpointResponseJSON,
)
from .track import Track
from .utils import TIDAL_API_URL
from .video import Video
Expand Down Expand Up @@ -234,7 +238,7 @@ def get(self, session: Session, audio_format: AudioFormat, out_dir: Path):
self.save_cover_image(session, out_dir)
try:
self.save_description()
except:
except Exception:
pass

_get_items = self.get_items(session, audio_format)
Expand Down Expand Up @@ -263,7 +267,7 @@ def request_mixes(session: Session, mix_id: str) -> Optional[SimpleNamespace]:
except HTTPError as he:
if resp.status_code == 404:
logger.warning(
f"404 Client Error: not found for TIDAL API endpoint pages/mix"
"404 Client Error: not found for TIDAL API endpoint pages/mix"
)
else:
logger.exception(he)
Expand Down
5 changes: 4 additions & 1 deletion tidal_wave/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,10 @@ class TidalPlaylist(TidalResource):
url: str

def __post_init__(self):
self.pattern: str = r"http(?:s)?://(?:listen\.)?tidal\.com/(?:browse/)?playlist/([0-9a-f]{8}\-[0-9a-f]{4}\-4[0-9a-f]{3}\-[89ab][0-9a-f]{3}\-[0-9a-f]{12})(?:.*?)?"
self.pattern: str = (
r"http(?:s)?://(?:listen\.)?tidal\.com/(?:browse/)?playlist/"
r"([0-9a-f]{8}\-[0-9a-f]{4}\-4[0-9a-f]{3}\-[89ab][0-9a-f]{3}\-[0-9a-f]{12})(?:.*?)?"
)

_id = self.match_url()

Expand Down
3 changes: 0 additions & 3 deletions tidal_wave/oauth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#!/usr/bin/env python3
#! -*- coding: utf-8 -*-

import base64
from dataclasses import dataclass, field
from datetime import datetime, timedelta, timezone
Expand Down
14 changes: 9 additions & 5 deletions tidal_wave/playlist.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
from dataclasses import dataclass, field
from dataclasses import dataclass
import json
import logging
from pathlib import Path
import shutil
import sys
from types import SimpleNamespace
from typing import Dict, List, Optional, Tuple, Union
from typing import Dict, List, Optional, Set, Tuple, Union

from requests import HTTPError, Session

from .media import AudioFormat
from .models import TracksEndpointResponseJSON, VideosEndpointResponseJSON
from .models import (
PlaylistsEndpointResponseJSON,
TracksEndpointResponseJSON,
VideosEndpointResponseJSON,
)
from .requesting import request_playlists
from .track import Track
from .utils import download_cover_image
from .utils import download_cover_image, TIDAL_API_URL
from .video import Video

logger = logging.getLogger("__name__")
Expand Down Expand Up @@ -240,7 +244,7 @@ def get(self, session: Session, audio_format: AudioFormat, out_dir: Path):
self.save_cover_image(session, out_dir)
try:
self.save_description()
except:
except Exception:
pass

_get_items = self.get_items(session, audio_format)
Expand Down
Loading

0 comments on commit 55a4ee6

Please sign in to comment.