Add Filmpalast A-Z browsing and document Gitea release upload
This commit is contained in:
@@ -21,6 +21,12 @@ ViewIT ist ein Kodi‑Addon zum Durchsuchen und Abspielen von Inhalten der unter
|
|||||||
- Standard-URL: `http://127.0.0.1:8080/repo/addons.xml`
|
- Standard-URL: `http://127.0.0.1:8080/repo/addons.xml`
|
||||||
- Optional eigene URL beim Build setzen: `REPO_BASE_URL=http://<host>:<port>/repo ./scripts/build_local_kodi_repo.sh`
|
- Optional eigene URL beim Build setzen: `REPO_BASE_URL=http://<host>:<port>/repo ./scripts/build_local_kodi_repo.sh`
|
||||||
|
|
||||||
|
## Gitea Release-Asset Upload
|
||||||
|
- ZIP bauen: `./scripts/build_kodi_zip.sh`
|
||||||
|
- Token setzen: `export GITEA_TOKEN=<token>`
|
||||||
|
- Asset an Tag hochladen (erstellt Release bei Bedarf): `./scripts/publish_gitea_release.sh`
|
||||||
|
- Optional: `--tag v0.1.50 --asset dist/plugin.video.viewit-0.1.50.zip`
|
||||||
|
|
||||||
## Entwicklung (kurz)
|
## Entwicklung (kurz)
|
||||||
- Hauptlogik: `addon/default.py`
|
- Hauptlogik: `addon/default.py`
|
||||||
- Plugins: `addon/plugins/*_plugin.py`
|
- Plugins: `addon/plugins/*_plugin.py`
|
||||||
|
|||||||
154
addon/default.py
154
addon/default.py
@@ -1018,6 +1018,9 @@ def _show_plugin_menu(plugin_name: str) -> None:
|
|||||||
if _plugin_has_capability(plugin, "genres"):
|
if _plugin_has_capability(plugin, "genres"):
|
||||||
_add_directory_item(handle, "Genres", "genres", {"plugin": plugin_name}, is_folder=True)
|
_add_directory_item(handle, "Genres", "genres", {"plugin": plugin_name}, is_folder=True)
|
||||||
|
|
||||||
|
if _plugin_has_capability(plugin, "alpha"):
|
||||||
|
_add_directory_item(handle, "A-Z", "alpha_index", {"plugin": plugin_name}, is_folder=True)
|
||||||
|
|
||||||
if _plugin_has_capability(plugin, "popular_series"):
|
if _plugin_has_capability(plugin, "popular_series"):
|
||||||
_add_directory_item(handle, "Meist gesehen", "popular", {"plugin": plugin_name, "page": "1"}, is_folder=True)
|
_add_directory_item(handle, "Meist gesehen", "popular", {"plugin": plugin_name, "page": "1"}, is_folder=True)
|
||||||
|
|
||||||
@@ -1729,6 +1732,149 @@ def _show_genre_titles_page(plugin_name: str, genre: str, page: int = 1) -> None
|
|||||||
xbmcplugin.endOfDirectory(handle)
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
|
||||||
|
|
||||||
|
def _show_alpha_index(plugin_name: str) -> None:
|
||||||
|
handle = _get_handle()
|
||||||
|
_log(f"A-Z laden: {plugin_name}")
|
||||||
|
plugin = _discover_plugins().get(plugin_name)
|
||||||
|
if plugin is None:
|
||||||
|
xbmcgui.Dialog().notification("A-Z", "Plugin nicht gefunden.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
return
|
||||||
|
getter = getattr(plugin, "alpha_index", None)
|
||||||
|
if not callable(getter):
|
||||||
|
xbmcgui.Dialog().notification("A-Z", "A-Z nicht verfügbar.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
letters = list(getter() or [])
|
||||||
|
except Exception as exc:
|
||||||
|
_log(f"A-Z konnte nicht geladen werden ({plugin_name}): {exc}", xbmc.LOGWARNING)
|
||||||
|
xbmcgui.Dialog().notification("A-Z", "A-Z konnte nicht geladen werden.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
return
|
||||||
|
for letter in letters:
|
||||||
|
letter = str(letter).strip()
|
||||||
|
if not letter:
|
||||||
|
continue
|
||||||
|
_add_directory_item(
|
||||||
|
handle,
|
||||||
|
letter,
|
||||||
|
"alpha_titles_page",
|
||||||
|
{"plugin": plugin_name, "letter": letter, "page": "1"},
|
||||||
|
is_folder=True,
|
||||||
|
)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
|
||||||
|
|
||||||
|
def _show_alpha_titles_page(plugin_name: str, letter: str, page: int = 1) -> None:
|
||||||
|
handle = _get_handle()
|
||||||
|
plugin = _discover_plugins().get(plugin_name)
|
||||||
|
if plugin is None:
|
||||||
|
xbmcgui.Dialog().notification("A-Z", "Plugin nicht gefunden.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
return
|
||||||
|
|
||||||
|
page = max(1, int(page or 1))
|
||||||
|
paging_getter = getattr(plugin, "titles_for_alpha_page", None)
|
||||||
|
if not callable(paging_getter):
|
||||||
|
xbmcgui.Dialog().notification("A-Z", "Paging nicht verfügbar.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
return
|
||||||
|
|
||||||
|
total_pages = None
|
||||||
|
count_getter = getattr(plugin, "alpha_page_count", None)
|
||||||
|
if callable(count_getter):
|
||||||
|
try:
|
||||||
|
total_pages = int(count_getter(letter) or 1)
|
||||||
|
except Exception:
|
||||||
|
total_pages = None
|
||||||
|
if total_pages is not None:
|
||||||
|
page = min(page, max(1, total_pages))
|
||||||
|
xbmcplugin.setPluginCategory(handle, f"{letter} ({page}/{total_pages})")
|
||||||
|
else:
|
||||||
|
xbmcplugin.setPluginCategory(handle, f"{letter} ({page})")
|
||||||
|
_set_content(handle, "movies" if (plugin_name or "").casefold() == "einschalten" else "tvshows")
|
||||||
|
|
||||||
|
if page > 1:
|
||||||
|
_add_directory_item(
|
||||||
|
handle,
|
||||||
|
"Vorherige Seite",
|
||||||
|
"alpha_titles_page",
|
||||||
|
{"plugin": plugin_name, "letter": letter, "page": str(page - 1)},
|
||||||
|
is_folder=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
titles = list(paging_getter(letter, page) or [])
|
||||||
|
except Exception as exc:
|
||||||
|
_log(f"A-Z Seite konnte nicht geladen werden ({plugin_name}/{letter} p{page}): {exc}", xbmc.LOGWARNING)
|
||||||
|
xbmcgui.Dialog().notification("A-Z", "Seite konnte nicht geladen werden.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
return
|
||||||
|
|
||||||
|
titles = [str(t).strip() for t in titles if t and str(t).strip()]
|
||||||
|
titles.sort(key=lambda value: value.casefold())
|
||||||
|
|
||||||
|
show_tmdb = _get_setting_bool("tmdb_genre_metadata", default=False)
|
||||||
|
if titles:
|
||||||
|
if show_tmdb:
|
||||||
|
with _busy_dialog():
|
||||||
|
tmdb_prefetched = _tmdb_labels_and_art_bulk(titles)
|
||||||
|
for title in titles:
|
||||||
|
info_labels, art, cast = tmdb_prefetched.get(title, _tmdb_labels_and_art(title))
|
||||||
|
info_labels = dict(info_labels or {})
|
||||||
|
info_labels.setdefault("mediatype", "tvshow")
|
||||||
|
if (info_labels.get("mediatype") or "").strip().casefold() == "tvshow":
|
||||||
|
info_labels.setdefault("tvshowtitle", title)
|
||||||
|
playstate = _title_playstate(plugin_name, title)
|
||||||
|
info_labels = _apply_playstate_to_info(dict(info_labels), playstate)
|
||||||
|
display_label = _label_with_duration(title, info_labels)
|
||||||
|
display_label = _label_with_playstate(display_label, playstate)
|
||||||
|
direct_play = bool(
|
||||||
|
plugin_name.casefold() == "einschalten"
|
||||||
|
and _get_setting_bool("einschalten_enable_playback", default=False)
|
||||||
|
)
|
||||||
|
_add_directory_item(
|
||||||
|
handle,
|
||||||
|
display_label,
|
||||||
|
"play_movie" if direct_play else "seasons",
|
||||||
|
{"plugin": plugin_name, "title": title, **_series_url_params(plugin, title)},
|
||||||
|
is_folder=not direct_play,
|
||||||
|
info_labels=info_labels,
|
||||||
|
art=art,
|
||||||
|
cast=cast,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
for title in titles:
|
||||||
|
playstate = _title_playstate(plugin_name, title)
|
||||||
|
direct_play = bool(
|
||||||
|
plugin_name.casefold() == "einschalten"
|
||||||
|
and _get_setting_bool("einschalten_enable_playback", default=False)
|
||||||
|
)
|
||||||
|
_add_directory_item(
|
||||||
|
handle,
|
||||||
|
_label_with_playstate(title, playstate),
|
||||||
|
"play_movie" if direct_play else "seasons",
|
||||||
|
{"plugin": plugin_name, "title": title, **_series_url_params(plugin, title)},
|
||||||
|
is_folder=not direct_play,
|
||||||
|
info_labels=_apply_playstate_to_info({"title": title}, playstate),
|
||||||
|
)
|
||||||
|
|
||||||
|
show_next = False
|
||||||
|
if total_pages is not None:
|
||||||
|
show_next = page < total_pages
|
||||||
|
|
||||||
|
if show_next:
|
||||||
|
_add_directory_item(
|
||||||
|
handle,
|
||||||
|
"Nächste Seite",
|
||||||
|
"alpha_titles_page",
|
||||||
|
{"plugin": plugin_name, "letter": letter, "page": str(page + 1)},
|
||||||
|
is_folder=True,
|
||||||
|
)
|
||||||
|
xbmcplugin.endOfDirectory(handle)
|
||||||
|
|
||||||
|
|
||||||
def _title_group_key(title: str) -> str:
|
def _title_group_key(title: str) -> str:
|
||||||
raw = (title or "").strip()
|
raw = (title or "").strip()
|
||||||
if not raw:
|
if not raw:
|
||||||
@@ -2708,6 +2854,14 @@ def run() -> None:
|
|||||||
params.get("genre", ""),
|
params.get("genre", ""),
|
||||||
_parse_positive_int(params.get("page", "1"), default=1),
|
_parse_positive_int(params.get("page", "1"), default=1),
|
||||||
)
|
)
|
||||||
|
elif action == "alpha_index":
|
||||||
|
_show_alpha_index(params.get("plugin", ""))
|
||||||
|
elif action == "alpha_titles_page":
|
||||||
|
_show_alpha_titles_page(
|
||||||
|
params.get("plugin", ""),
|
||||||
|
params.get("letter", ""),
|
||||||
|
_parse_positive_int(params.get("page", "1"), default=1),
|
||||||
|
)
|
||||||
elif action == "genre_series_group":
|
elif action == "genre_series_group":
|
||||||
_show_genre_series_group(
|
_show_genre_series_group(
|
||||||
params.get("plugin", ""),
|
params.get("plugin", ""),
|
||||||
|
|||||||
@@ -227,6 +227,8 @@ class FilmpalastPlugin(BasisPlugin):
|
|||||||
self._hoster_cache: Dict[str, Dict[str, str]] = {}
|
self._hoster_cache: Dict[str, Dict[str, str]] = {}
|
||||||
self._genre_to_url: Dict[str, str] = {}
|
self._genre_to_url: Dict[str, str] = {}
|
||||||
self._genre_page_count_cache: Dict[str, int] = {}
|
self._genre_page_count_cache: Dict[str, int] = {}
|
||||||
|
self._alpha_to_url: Dict[str, str] = {}
|
||||||
|
self._alpha_page_count_cache: Dict[str, int] = {}
|
||||||
self._requests_available = REQUESTS_AVAILABLE
|
self._requests_available = REQUESTS_AVAILABLE
|
||||||
self._default_preferred_hosters: List[str] = list(DEFAULT_PREFERRED_HOSTERS)
|
self._default_preferred_hosters: List[str] = list(DEFAULT_PREFERRED_HOSTERS)
|
||||||
self._preferred_hosters: List[str] = list(self._default_preferred_hosters)
|
self._preferred_hosters: List[str] = list(self._default_preferred_hosters)
|
||||||
@@ -495,7 +497,79 @@ class FilmpalastPlugin(BasisPlugin):
|
|||||||
return max_page
|
return max_page
|
||||||
|
|
||||||
def capabilities(self) -> set[str]:
|
def capabilities(self) -> set[str]:
|
||||||
return {"genres"}
|
return {"genres", "alpha"}
|
||||||
|
|
||||||
|
def _parse_alpha_links(self, soup: BeautifulSoupT) -> Dict[str, str]:
|
||||||
|
alpha: Dict[str, str] = {}
|
||||||
|
if not soup:
|
||||||
|
return alpha
|
||||||
|
for anchor in soup.select("section#movietitle a[href], #movietitle a[href], aside #movietitle a[href]"):
|
||||||
|
name = (anchor.get_text(" ", strip=True) or "").strip()
|
||||||
|
href = (anchor.get("href") or "").strip()
|
||||||
|
if not name or not href:
|
||||||
|
continue
|
||||||
|
if "/search/alpha/" not in href:
|
||||||
|
continue
|
||||||
|
if name in alpha:
|
||||||
|
continue
|
||||||
|
alpha[name] = _absolute_url(href)
|
||||||
|
return alpha
|
||||||
|
|
||||||
|
def alpha_index(self) -> List[str]:
|
||||||
|
if not self._requests_available:
|
||||||
|
return []
|
||||||
|
if self._alpha_to_url:
|
||||||
|
return list(self._alpha_to_url.keys())
|
||||||
|
try:
|
||||||
|
soup = _get_soup(_absolute_url("/"), session=get_requests_session("filmpalast", headers=HEADERS))
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
parsed = self._parse_alpha_links(soup)
|
||||||
|
if parsed:
|
||||||
|
self._alpha_to_url = dict(parsed)
|
||||||
|
return list(self._alpha_to_url.keys())
|
||||||
|
|
||||||
|
def alpha_page_count(self, letter: str) -> int:
|
||||||
|
letter = (letter or "").strip()
|
||||||
|
if not letter:
|
||||||
|
return 1
|
||||||
|
if letter in self._alpha_page_count_cache:
|
||||||
|
return max(1, int(self._alpha_page_count_cache.get(letter, 1)))
|
||||||
|
if not self._alpha_to_url:
|
||||||
|
self.alpha_index()
|
||||||
|
base_url = self._alpha_to_url.get(letter, "")
|
||||||
|
if not base_url:
|
||||||
|
return 1
|
||||||
|
try:
|
||||||
|
soup = _get_soup(base_url, session=get_requests_session("filmpalast", headers=HEADERS))
|
||||||
|
except Exception:
|
||||||
|
return 1
|
||||||
|
pages = self._extract_last_page(soup)
|
||||||
|
self._alpha_page_count_cache[letter] = max(1, pages)
|
||||||
|
return self._alpha_page_count_cache[letter]
|
||||||
|
|
||||||
|
def titles_for_alpha_page(self, letter: str, page: int) -> List[str]:
|
||||||
|
letter = (letter or "").strip()
|
||||||
|
if not letter or not self._requests_available:
|
||||||
|
return []
|
||||||
|
if not self._alpha_to_url:
|
||||||
|
self.alpha_index()
|
||||||
|
base_url = self._alpha_to_url.get(letter, "")
|
||||||
|
if not base_url:
|
||||||
|
return []
|
||||||
|
page = max(1, int(page or 1))
|
||||||
|
url = base_url if page == 1 else urljoin(base_url.rstrip("/") + "/", f"page/{page}")
|
||||||
|
try:
|
||||||
|
soup = _get_soup(url, session=get_requests_session("filmpalast", headers=HEADERS))
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
hits = self._parse_listing_hits(soup)
|
||||||
|
return self._apply_hits_to_title_index(hits)
|
||||||
|
|
||||||
|
def titles_for_alpha(self, letter: str) -> List[str]:
|
||||||
|
titles = self.titles_for_alpha_page(letter, 1)
|
||||||
|
titles.sort(key=lambda value: value.casefold())
|
||||||
|
return titles
|
||||||
|
|
||||||
def genres(self) -> List[str]:
|
def genres(self) -> List[str]:
|
||||||
if not self._requests_available:
|
if not self._requests_available:
|
||||||
|
|||||||
193
scripts/publish_gitea_release.sh
Executable file
193
scripts/publish_gitea_release.sh
Executable file
@@ -0,0 +1,193 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ADDON_XML="${ROOT_DIR}/addon/addon.xml"
|
||||||
|
DEFAULT_NOTES="Automatischer Release-Upload aus ViewIT Build."
|
||||||
|
|
||||||
|
TAG=""
|
||||||
|
ASSET_PATH=""
|
||||||
|
TITLE=""
|
||||||
|
NOTES="${DEFAULT_NOTES}"
|
||||||
|
DRY_RUN="0"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--tag)
|
||||||
|
TAG="${2:-}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--asset)
|
||||||
|
ASSET_PATH="${2:-}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--title)
|
||||||
|
TITLE="${2:-}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--notes)
|
||||||
|
NOTES="${2:-}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
DRY_RUN="1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unbekanntes Argument: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -f "${ADDON_XML}" ]]; then
|
||||||
|
echo "Missing: ${ADDON_XML}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -r ADDON_ID ADDON_VERSION < <(python3 - "${ADDON_XML}" <<'PY'
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
root = ET.parse(sys.argv[1]).getroot()
|
||||||
|
print(root.attrib.get("id", "plugin.video.viewit"), root.attrib.get("version", "0.0.0"))
|
||||||
|
PY
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ -z "${TAG}" ]]; then
|
||||||
|
TAG="v${ADDON_VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${ASSET_PATH}" ]]; then
|
||||||
|
ASSET_PATH="${ROOT_DIR}/dist/${ADDON_ID}-${ADDON_VERSION}.zip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "${ASSET_PATH}" ]]; then
|
||||||
|
echo "Asset nicht gefunden, baue ZIP: ${ASSET_PATH}"
|
||||||
|
"${ROOT_DIR}/scripts/build_kodi_zip.sh" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "${ASSET_PATH}" ]]; then
|
||||||
|
echo "Asset fehlt nach Build: ${ASSET_PATH}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${TITLE}" ]]; then
|
||||||
|
TITLE="ViewIT ${TAG}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
REMOTE_URL="$(git -C "${ROOT_DIR}" remote get-url origin)"
|
||||||
|
|
||||||
|
read -r BASE_URL OWNER REPO < <(python3 - "${REMOTE_URL}" <<'PY'
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
u = sys.argv[1].strip()
|
||||||
|
m = re.match(r"^https?://([^/]+)/([^/]+)/([^/.]+)(?:\.git)?/?$", u)
|
||||||
|
if not m:
|
||||||
|
raise SystemExit("Origin-URL muss https://host/owner/repo(.git) sein.")
|
||||||
|
host, owner, repo = m.group(1), m.group(2), m.group(3)
|
||||||
|
print(f"https://{host}", owner, repo)
|
||||||
|
PY
|
||||||
|
)
|
||||||
|
|
||||||
|
API_BASE="${BASE_URL}/api/v1/repos/${OWNER}/${REPO}"
|
||||||
|
ASSET_NAME="$(basename "${ASSET_PATH}")"
|
||||||
|
|
||||||
|
if [[ "${DRY_RUN}" == "1" ]]; then
|
||||||
|
echo "[DRY-RUN] API: ${API_BASE}"
|
||||||
|
echo "[DRY-RUN] Tag: ${TAG}"
|
||||||
|
echo "[DRY-RUN] Asset: ${ASSET_PATH}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${GITEA_TOKEN:-}" ]]; then
|
||||||
|
echo "Bitte GITEA_TOKEN setzen." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmp_json="$(mktemp)"
|
||||||
|
tmp_http="$(mktemp)"
|
||||||
|
trap 'rm -f "${tmp_json}" "${tmp_http}"' EXIT
|
||||||
|
|
||||||
|
urlenc() {
|
||||||
|
python3 - "$1" <<'PY'
|
||||||
|
import sys
|
||||||
|
from urllib.parse import quote
|
||||||
|
print(quote(sys.argv[1], safe=""))
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
tag_enc="$(urlenc "${TAG}")"
|
||||||
|
auth_header="Authorization: token ${GITEA_TOKEN}"
|
||||||
|
|
||||||
|
http_code="$(curl -sS -H "${auth_header}" -o "${tmp_json}" -w "%{http_code}" "${API_BASE}/releases/tags/${tag_enc}")"
|
||||||
|
|
||||||
|
if [[ "${http_code}" == "200" ]]; then
|
||||||
|
RELEASE_ID="$(python3 - "${tmp_json}" <<'PY'
|
||||||
|
import json,sys
|
||||||
|
print(json.load(open(sys.argv[1], encoding="utf-8"))["id"])
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
elif [[ "${http_code}" == "404" ]]; then
|
||||||
|
payload="$(python3 - "${TAG}" "${TITLE}" "${NOTES}" <<'PY'
|
||||||
|
import json,sys
|
||||||
|
print(json.dumps({
|
||||||
|
"tag_name": sys.argv[1],
|
||||||
|
"name": sys.argv[2],
|
||||||
|
"body": sys.argv[3],
|
||||||
|
"draft": False,
|
||||||
|
"prerelease": False
|
||||||
|
}))
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
http_code_create="$(curl -sS -X POST -H "${auth_header}" -H "Content-Type: application/json" -d "${payload}" -o "${tmp_json}" -w "%{http_code}" "${API_BASE}/releases")"
|
||||||
|
if [[ "${http_code_create}" != "201" ]]; then
|
||||||
|
echo "Release konnte nicht erstellt werden (HTTP ${http_code_create})." >&2
|
||||||
|
cat "${tmp_json}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
RELEASE_ID="$(python3 - "${tmp_json}" <<'PY'
|
||||||
|
import json,sys
|
||||||
|
print(json.load(open(sys.argv[1], encoding="utf-8"))["id"])
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
else
|
||||||
|
echo "Release-Abfrage fehlgeschlagen (HTTP ${http_code})." >&2
|
||||||
|
cat "${tmp_json}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
assets_code="$(curl -sS -H "${auth_header}" -o "${tmp_json}" -w "%{http_code}" "${API_BASE}/releases/${RELEASE_ID}/assets")"
|
||||||
|
if [[ "${assets_code}" == "200" ]]; then
|
||||||
|
EXISTING_ASSET_ID="$(python3 - "${tmp_json}" "${ASSET_NAME}" <<'PY'
|
||||||
|
import json,sys
|
||||||
|
assets=json.load(open(sys.argv[1], encoding="utf-8"))
|
||||||
|
name=sys.argv[2]
|
||||||
|
for a in assets:
|
||||||
|
if a.get("name")==name:
|
||||||
|
print(a.get("id"))
|
||||||
|
break
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
if [[ -n "${EXISTING_ASSET_ID}" ]]; then
|
||||||
|
del_code="$(curl -sS -X DELETE -H "${auth_header}" -o "${tmp_http}" -w "%{http_code}" "${API_BASE}/releases/${RELEASE_ID}/assets/${EXISTING_ASSET_ID}")"
|
||||||
|
if [[ "${del_code}" != "204" ]]; then
|
||||||
|
echo "Altes Asset konnte nicht geloescht werden (HTTP ${del_code})." >&2
|
||||||
|
cat "${tmp_http}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
asset_name_enc="$(urlenc "${ASSET_NAME}")"
|
||||||
|
upload_code="$(curl -sS -X POST -H "${auth_header}" -F "attachment=@${ASSET_PATH}" -o "${tmp_json}" -w "%{http_code}" "${API_BASE}/releases/${RELEASE_ID}/assets?name=${asset_name_enc}")"
|
||||||
|
if [[ "${upload_code}" != "201" ]]; then
|
||||||
|
echo "Asset-Upload fehlgeschlagen (HTTP ${upload_code})." >&2
|
||||||
|
cat "${tmp_json}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Release-Asset hochgeladen:"
|
||||||
|
echo " Repo: ${OWNER}/${REPO}"
|
||||||
|
echo " Tag: ${TAG}"
|
||||||
|
echo " Asset: ${ASSET_NAME}"
|
||||||
|
echo " URL: ${BASE_URL}/${OWNER}/${REPO}/releases/tag/${TAG}"
|
||||||
Reference in New Issue
Block a user