diff --git a/bin/build_github_docker.sh b/bin/build_github_docker.sh index b7e2b5eb8..ee9852a91 100755 --- a/bin/build_github_docker.sh +++ b/bin/build_github_docker.sh @@ -1,35 +1,57 @@ #!/bin/bash -set -e -set -o pipefail +set -euo pipefail source "${HOME}/.ghcr.io" -if [ -f "../target/x86_64-unknown-linux-musl/release/m3u-filter" ]; then - echo "Static binary does not exists." - exit; -fi -if [ -d "../frontend/build" ]; then - echo "Web directory does not exists." - exit; +# Check if the binary exists +if [ ! -f "./target/x86_64-unknown-linux-musl/release/m3u-filter" ]; then + echo "Error: Static binary '../target/x86_64-unknown-linux-musl/release/m3u-filter' does not exist." + exit 1 fi +# Check if the frontend build directory exists +if [ ! -d "./frontend/build" ]; then + echo "Error: Web directory '../frontend/build' does not exist." + exit 1 +fi + +# Prepare Docker build context cd ./docker cp ../target/x86_64-unknown-linux-musl/release/m3u-filter . rm -rf ./web cp -r ../frontend/build ./web +# Get the version from the binary VERSION=$(./m3u-filter -V | sed 's/m3u-filter *//') -if [ -n "${VERSION}" ]; then - echo "Building Docker image version ${VERSION}" - - docker build -f Dockerfile-manual -t ghcr.io/euzu/m3u-filter:"${VERSION}" . - docker tag ghcr.io/euzu/m3u-filter:"${VERSION}" ghcr.io/euzu/m3u-filter:latest - - docker login ghcr.io -u euzu -p "${GHCR_IO_TOKEN}" - - docker push ghcr.io/euzu/m3u-filter:"${VERSION}" - docker push ghcr.io/euzu/m3u-filter:latest - - rm -rf ./web - rm -f ./m3u-filter +if [ -z "${VERSION}" ]; then + echo "Error: Failed to determine the version from the binary." + exit 1 fi + +echo "Building Docker images for version ${VERSION}" + +# Build scratch image and tag as "latest" +docker build -f Dockerfile-manual -t ghcr.io/euzu/m3u-filter:"${VERSION}" --target scratch-final . +docker tag ghcr.io/euzu/m3u-filter:"${VERSION}" ghcr.io/euzu/m3u-filter:latest + +# Build alpine image and tag as "latest" +docker build -f Dockerfile-manual -t ghcr.io/euzu/m3u-filter-alpine:"${VERSION}" --target alpine-final . +docker tag ghcr.io/euzu/m3u-filter-alpine:"${VERSION}" ghcr.io/euzu/m3u-filter-alpine:latest + +echo "Logging into GitHub Container Registry..." +docker login ghcr.io -u euzu -p "${GHCR_IO_TOKEN}" + +# Push scratch +docker push ghcr.io/euzu/m3u-filter:"${VERSION}" +docker push ghcr.io/euzu/m3u-filter:latest + +# Push alpine +docker push ghcr.io/euzu/m3u-filter-alpine:"${VERSION}" +docker push ghcr.io/euzu/m3u-filter-alpine:latest + +# Clean up +echo "Cleaning up build artifacts..." +rm -rf ./web +rm -f ./m3u-filter + +echo "Docker images for version ${VERSION} have been successfully built, tagged, and pushed." diff --git a/docker/Dockerfile b/docker/Dockerfile index 493fab18c..f422977a5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -31,7 +31,7 @@ RUN yarn build RUN rm -rf node_modules # Final container -FROM scratch +FROM scratch as scratch-final WORKDIR / COPY --from=rust-build /usr/share/zoneinfo /usr/share/zoneinfo @@ -44,3 +44,18 @@ COPY --from=node-build /app/build /web ENTRYPOINT ["/m3u-filter"] CMD ["-s", "-p", "/config"] + +# Final container +FROM alpine:latest as alpine-final + +RUN apk add --no-cache bash curl + +WORKDIR /app + +COPY --from=rust-build /src/target/x86_64-unknown-linux-musl/release/m3u-filter m3u-filter +COPY --from=node-build /app/build web +# config should be mounted as volume +# COPY ./config config + +ENTRYPOINT ["/app/m3u-filter"] +CMD ["-s", "-p", "/app/config"] \ No newline at end of file diff --git a/docker/Dockerfile-manual b/docker/Dockerfile-manual index 2450fd90c..71d8f6dc6 100644 --- a/docker/Dockerfile-manual +++ b/docker/Dockerfile-manual @@ -1,7 +1,7 @@ FROM gcr.io/distroless/base-debian12 as build - -FROM scratch +# Scratch Final container +FROM scratch as scratch-final WORKDIR / COPY --from=build /usr/share/zoneinfo /usr/share/zoneinfo @@ -11,3 +11,18 @@ COPY ./m3u-filter / COPY ./web /web CMD ["./m3u-filter", "-s", "-p", "/config"] + +# Alpine Final container +FROM alpine:latest as alpine-final + +RUN apk add --no-cache bash curl strace tcpdump bind-tools nano + +WORKDIR /app + +COPY ./m3u-filter . +COPY ./web ./web +# config should be mounted as volume +# COPY ./config ./config + +ENTRYPOINT ["/app/m3u-filter"] +CMD ["-s", "-p", "/app/config"] \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index f5a2d5a0d..57da1b8ac 100644 --- a/docker/README.md +++ b/docker/README.md @@ -2,8 +2,9 @@ Change into the root directory and run: ```shell -docker build --rm -f docker/Dockerfile -t m3u-filter . +docker build --rm -f docker/Dockerfile -t m3u-filter --target scratch-final . ``` +PS: If you build `alpine-final` target be aware of the path prefix: `/app` This will build the complete project and create a docker image. diff --git a/src/model/playlist.rs b/src/model/playlist.rs index 27ea74a57..7ab5c4ebb 100644 --- a/src/model/playlist.rs +++ b/src/model/playlist.rs @@ -111,16 +111,11 @@ pub(crate) struct PlaylistItemHeader { impl PlaylistItemHeader { pub(crate) fn gen_uuid(&mut self) { - let cluster = self.xtream_cluster as u8; - let base_url = get_base_url(&self.url).unwrap_or_else(|| self.url.to_string()); + //let base_url = get_base_url(&self.url).unwrap_or_else(|| self.url.to_string()); // Create a Blake3 hasher let mut hasher = Hasher::new(); - hasher.update(base_url.as_bytes()); - // hasher.update(self.stream_id.as_bytes()); - // hasher.update(self.title.as_bytes()); - // hasher.update(self.name.as_bytes()); - // hasher.update(self.group.as_bytes()); - hasher.update(&[cluster]); + // the url should be different for each entry. + hasher.update(self.url.as_bytes()); // Finalize and get the hash result let hash_bytes = hasher.finalize(); // Encode the reduced 128-bit hash to Base62 diff --git a/src/processing/m3u_parser.rs b/src/processing/m3u_parser.rs index 57110db60..6c4b05231 100644 --- a/src/processing/m3u_parser.rs +++ b/src/processing/m3u_parser.rs @@ -7,17 +7,19 @@ use crate::model::playlist::{PlaylistGroup, PlaylistItem, PlaylistItemHeader, Pl use crate::utils::default_utils::{default_as_empty_rc_str, default_playlist_item_type, default_stream_cluster}; use crate::utils::string_utils; +#[inline] fn token_value(it: &mut std::str::Chars) -> String { - if let Some(oc) = it.next() { - if oc == '"' { - return get_value(it); - } + // Use .find() to skip until the first double quote (") character. + if it.find(|&ch| ch == '"').is_some() { + // If a quote is found, call get_value to extract the value. + return get_value(it); } + // If no double quote is found, return an empty string. String::new() } fn get_value(it: &mut std::str::Chars) -> String { - let mut result = String::with_capacity(512); + let mut result = String::with_capacity(128); for oc in it.by_ref() { if oc == '"' { break; @@ -29,13 +31,14 @@ fn get_value(it: &mut std::str::Chars) -> String { } fn token_till(it: &mut std::str::Chars, stop_char: char, start_with_alpha: bool) -> Option { - let mut result = String::with_capacity(512); + let mut result = String::with_capacity(128); let mut skip_non_alpha = start_with_alpha; for ch in it.by_ref() { if ch == stop_char { break; - } else if ch.is_whitespace() && result.is_empty() { + } + if result.is_empty() && ch.is_whitespace() { continue; } @@ -57,6 +60,7 @@ fn token_till(it: &mut std::str::Chars, stop_char: char, start_with_alpha: bool) } } +#[inline] fn skip_digit(it: &mut std::str::Chars) -> Option { loop { match it.next() { @@ -154,7 +158,7 @@ fn process_header(input: &ConfigInput, video_suffixes: &Vec<&str>, content: &str } { - let mut header = plih.borrow_mut(); + let header = plih.borrow_mut(); if header.name.is_empty() { if !header.title.is_empty() { header.name = header.title.clone();