#!/bin/bash
#
# spotify-easyrpm is a script which can download the latest debian package from the Spotify
# repository and convert it into an RPM. It is also capable of installing, scheduling and storing
# the RPMs in a local filesystem repo for installing Spotify updates alongside regular system updates
#
# Run "spotify-easyrpm --help" for more info
#

#set -x


V_PRG_NAME="spotify-easyrpm"
V_CONFIG_FILE="${HOME}/.${V_PRG_NAME}"

V_SYS_ARCH="$(uname -i)"

V_PKGNAME="spotify-client"
V_HTTP_REPO="http://repository.spotify.com/pool/non-free/s/${V_PKGNAME}/"

V_SOURCES_DIR="${HOME}/rpmbuild/SOURCES"
V_SPECS_DIR="${HOME}/rpmbuild/SPECS"
V_RPMS_DIR="${HOME}/rpmbuild/RPMS"
V_BUILDROOT_DIR="${HOME}/rpmbuild/BUILDROOT"

SYSTEMD_UNIT_DIR="${HOME}/.local/share/systemd/user"
SYSTEMD_UNIT="${SYSTEMD_UNIT_DIR}/${V_PRG_NAME}.service"
SYSTEMD_TIMER="${SYSTEMD_UNIT_DIR}/${V_PRG_NAME}.timer"
V_LOCAL_REPO="/var/cache/${V_PRG_NAME}"


f_logo() {
clear
cat <<EOF

┌─┐┌─┐┌─┐┌┬┐┬┌─┐┬ ┬   ┌─┐┌─┐┌─┐┬ ┬┬─┐┌─┐┌┬┐
└─┐├─┘│ │ │ │├┤ └┬┘───├┤ ├─┤└─┐└┬┘├┬┘├─┘│││
└─┘┴  └─┘ ┴ ┴└   ┴    └─┘┴ ┴└─┘ ┴ ┴└─┴  ┴ ┴

EOF
sleep 2
cat <<EOF
VERSION: 2.1.0
SUPPORT: https://github.com/megamaced/spotify-easyrpm/issues
The latest openSUSE Leap, Tumbleweed or SLE are supported only

MODE: ${V_RUN_MODE}
EOF
}


f_help() {
cat <<EOF

${V_PRG_NAME} is a script which can download the latest debian package from the Spotify
repository and convert it into an RPM. It is also capable of installing, scheduling and storing
the RPMs in a local filesystem repo for installing Spotify updates alongside regular system updates


 ${V_PRG_NAME}

  - Regular prompt based mode to create an RPM and optionally install and create an update schedule

 ${V_PRG_NAME} --quiet

  - Create the RPM
  - Install the Spotify RPM
  - Set up a daily scheduled update job
  - Set up a local filesystem repo

 ${V_PRG_NAME} --create-schedule

  - If you previously opted out creating an automated update schedule but now desire it

 ${V_PRG_NAME} --remove-schedule

  - Removes the schedule and local repo if present

 ${V_PRG_NAME} --clean-repo

  - Cleans up old versions from the local filesystem repo


EOF
 exit 0
}


f_error() {
echo "$1" 1>&2
f_cleanup
exit 1
}


f_cleanup() {
rm "${V_SOURCES_DIR}"/index.html > /dev/null 2>&1
rm "${V_SOURCES_DIR}"/data.tar.gz > /dev/null 2>&1
rm -r "${V_SOURCES_DIR:?}"/usr > /dev/null 2>&1
rm -r "${V_SOURCES_DIR:?}"/"${V_PKGNAME}"* > /dev/null 2>&1
rm -r "${V_BUILDROOT_DIR:?}"/"${V_PKGNAME}"* > /dev/null 2>&1
}


f_root_check() {
 if [[ "$(id -u)" == "0" ]]; then
  f_error "Do not run as root"
 fi
}


f_arch_check() {
 if [[ "${V_SYS_ARCH}" == i386 ]]; then
  V_DEB_ARCH=i386
  V_RPM_ARCH=i586
 elif [[ "${V_SYS_ARCH}" == x86_64 ]]; then
  V_DEB_ARCH=amd64
  V_RPM_ARCH=x86_64
 else
  f_error "Unsupported architecture. Aborting"
 fi
}


f_config() {
 if [ -f "${V_CONFIG_FILE}" ]; then
  source "${V_CONFIG_FILE}"
 else
  cat << EOF > "${V_CONFIG_FILE}"

# PREFS
PREF_PROMPT_SCHEDULE=YES

EOF
 fi
}


f_download() {
echo "Downloading the latest Spotify deb"
if ! wget -P "${V_SOURCES_DIR}"/ "${V_HTTP_REPO}"/"${V_REPO_LATEST_DEB}"; then
f_error "Failed to download Spotify. Aborting"
fi
}


f_set_deb_ver() {
V_REPO_LATEST_DEB="$(curl -s --list-only "${V_HTTP_REPO}" | grep -wo "${V_PKGNAME}".*"${V_DEB_ARCH}".deb | cut -f2 -d">" | sort | tail -n1)"
V_DEB_VER="$(echo $V_REPO_LATEST_DEB | cut -f2 -d"_" | cut -f1 -d"-")"
}


f_create_rpmbuild_dirs() {
echo "Creating build dirs in ${HOME}/rpmbuild"
if ! mkdir -p "${HOME}"/rpmbuild/{BUILD,BUILDROOT,OTHER,RPMS,SOURCES,SPECS,SRPMS}; then
f_error "Failed to create rpmbuild root. Aborting"
fi
V_RPMBUILD_OWNER_CHECK="$(find "${HOME}"/rpmbuild -not -user "$(id -u)")"
if [[ ! -z "${V_RPMBUILD_OWNER_CHECK}" ]]; then
  echo "Detected some directories / files not owned by you. Fixing ${V_RPMBUILD_OWNER_CHECK}"
  for i in ${V_RPMBUILD_OWNER_CHECK}; do
    sudo chown "$(id -u)" "$i"
  done
fi
if [[ ! -f "${HOME}"/.rpmmacros ]]; then
 echo "Creating ${HOME}/.rpmmacros"
 cat << EOF >> "${HOME}"/.rpmmacros
# Generated by ${V_PRG_NAME}
%_topdir ${HOME}/rpmbuild
EOF
fi
}


f_extract_deb() {
echo "Extracting deb and preparing"
ar -x "${V_SOURCES_DIR}"/"${V_PKGNAME}"*"${V_DEB_ARCH}".deb || f_error "Failed to extract deb"
rm control.tar.gz debian-binary
mv data.tar.gz "${V_SOURCES_DIR}"/
tar xzf "${V_SOURCES_DIR}"/data.tar.gz -C "${V_SOURCES_DIR}"/
mkdir -p "${V_SOURCES_DIR}"/"${V_PKGNAME}"
mv "${V_SOURCES_DIR}"/usr "${V_SOURCES_DIR}"/"${V_PKGNAME}"/
}


f_script_location_check() {
if [[ ! -f /usr/bin/"${V_PRG_NAME}" ]] || ! diff ${0} /usr/bin/"${V_PRG_NAME}" > /dev/null 2>&1; then
 echo "Copying ${V_PRG_NAME} to /usr/bin/${V_PRG_NAME} for the schedule to work"
 sudo cp ${0} /usr/bin/"${V_PRG_NAME}"
fi
}


f_schedule_prompt() {
echo "Checking for an existing schedule"
 if [[ ! -f "${SYSTEMD_TIMER}" ]]; then
  if [[ "${V_RUN_MODE}" == "create-schedule" ]] || [[ "${PREF_PROMPT_SCHEDULE}" != "NO" ]]; then
  while true
  do
   read -rp "Do you wish to set up an automated update schedule (y/n)?" Q_SCHEDULE_ANSWER

  case $Q_SCHEDULE_ANSWER in
  y ) f_create_repo
      f_create_systemd_unit
      f_script_location_check
      break;;

  n ) echo "Ok skipping...If you want to create this in the future just run ${V_PRG_NAME} -create-schedule"
      sed -i "s/\(PREF_PROMPT_SCHEDULE=\)\(.*\)/\1NO/" "${V_CONFIG_FILE}"
      break;;

  esac
 done
else
  echo "Skipping schedule prompt as you previously opted out"
 fi
else
  echo "Found existing schedule. Skipping"
  f_update_local_repo
fi
}


f_remove_schedule() {
 if [[ -f "${SYSTEMD_UNIT}" ]]; then
  echo "Removing ${V_PRG_NAME} from your systemd unit files"
  systemctl --user disable spotify-easyrpm
  rm "${SYSTEMD_UNIT}"
  systemctl --user daemon-reload
 fi
 if [[ -f "${SYSTEMD_TIMER}" ]]; then
  echo "Removing ${V_PRG_NAME} from your systemd timers"
  systemctl --user disable spotify-easyrpm.timer
  rm "${SYSTEMD_TIMER}"
  systemctl --user daemon-reload
 fi
}

f_remove_repo() {
 if [[ -f /etc/zypp/repos.d/${V_PRG_NAME}.repo ]]; then
  echo "Removing ${V_PRG_NAME} zypper repo"
  sudo zypper rr "${V_PRG_NAME}"
 fi
 if [[ -d "${V_LOCAL_REPO}" ]]; then
  echo "Removing ${V_PRG_NAME} repo from filesystem"
  sudo rm -r "${V_LOCAL_REPO}"
 fi
}

f_install_build_deps() {
if ! rpm -q rpm-build > /dev/null 2>&1; then
 echo "Installing build dependencies (rpm-build)"
 if ! sudo zypper --non-interactive in rpm-build; then
 f_error "Failed to install build dependencies. Aborting"
 fi
fi
if ! rpm -q update-desktop-files > /dev/null 2>&1; then
 echo "Installing build dependencies (update-desktop-files)"
 if ! sudo zypper --non-interactive in update-desktop-files; then
 f_error "Failed to install build dependencies. Aborting"
 fi
fi
}

f_prepare_src() {
echo "Preparing RPM src tarball"
mkdir -p "${V_SOURCES_DIR}"/"${V_PKGNAME}"/usr/share/applications
f_desktop_entry
tar czf "${V_SOURCES_DIR}"/"${V_PKGNAME}"-"${V_DEB_VER}".tar.gz -C "${V_SOURCES_DIR}"/ "${V_PKGNAME}"
}


f_desktop_entry() {
cat << EOF > "${V_SOURCES_DIR}"/"${V_PKGNAME}"/usr/share/applications/spotify.desktop
[Desktop Entry]
Name=Spotify
GenericName=Music Player
Comment=Spotify streaming music client
Icon=/usr/share/spotify/icons/spotify-linux-64.png
Exec=spotify %U
TryExec=spotify
Terminal=false
Type=Application
Categories=Audio;Music;Player;AudioVideo;
MimeType=x-scheme-handler/spotify;
EOF
}


f_ver_compare() {
echo "Comparing debian repo version to installed or local machine repo version (if any)"
if [[ "$(rpm -q "${V_PKGNAME}" | cut -f3 -d"-")" == "${V_DEB_VER}" ]] || [[ "$(find ${V_LOCAL_REPO} -type f -name "*.rpm" | sort | tail -n1 | cut -f4 -d"-")" == "${V_DEB_VER}" ]] ; then
 if [[ "${V_RUN_MODE}" != "prompt" ]]; then
  echo "spotify-client ${V_DEB_VER} is already installed or available from local machine repo. Quitting"
  f_cleanup
  exit 0
 else
 while true
  do
   read -rp "The latest version in the repo is ${V_DEB_VER} which is already installed. Continue? (y/n)" Q_SAME_VER_CONTINUE
    case $Q_SAME_VER_CONTINUE in

      y ) echo "ok"
      break;;

      n ) f_schedule_prompt
          f_cleanup
          echo "bye"
      exit;;

   esac
 done
 fi
fi
}


f_rpm_spec() {
echo "Writing new build file"

cat << EOF > "${V_SPECS_DIR}"/spotify.spec
#
# spec file for package ${V_PKGNAME}
#
# Copyright (c) 2018 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.

# Please submit bugfixes or comments via http://bugs.opensuse.org/
#

Name:   ${V_PKGNAME}
Version:  ${V_DEB_VER}
Release:  0
License:  https://www.spotify.com/legal/end-user-agreement
Summary:  Spotify streaming music client
Vendor:   Spotify AB
Url:    https://www.spotify.com
Source:   %{name}-%{version}.tar.gz
BuildRoot:  %{_tmppath}/%{name}-%{version}-build
BuildRequires:  update-desktop-files
Requires: libasound2
Requires: libatomic1
Requires: libcurl4
Requires: gconf2
Requires: libgtk-2_0-0
Requires: libglib-2_0-0
Requires: libgcrypt20
Requires: mozilla-nss
Requires: libudev1
Requires: libX11-6
Requires: libXtst6
%if 0%{?sle_version} <= 150000 && 0%{?is_opensuse} || 0%{?sle_version} <= 150000 && !0%{?is_opensuse}
Requires: libopenssl1_0_0
%else
Requires: libopenssl1_1
%endif
Requires: xdg-utils
Recommends: libavcodec56
Recommends: libavformat56
Recommends: zenity
Suggests: libnotify4
AutoReq:  no

%description
The Spotify desktop client unofficially supports Linux, meaning that there is a
native client for Linux but we do not offer official support for client-related
problems on this platform. If you are having severe problems with the native
Linux client, there are a few alternatives that you can try:

- Using the web player: https://play.spotify.com (requires Adobe Flash plugin)
- Running the native Windows client in Wine (not recommended, but should work)

Otherwise, the native Linux client is the recommended way to listen to Spotify
on Linux systems.

%prep
%setup -q -n %{name}

%install
mkdir -p %{buildroot}%{_prefix}
cp -r usr %{buildroot}/

%post

%desktop_database_post

if [[ ! -f %{_libdir}/libcurl-gnutls.so.4 ]]; then
 ln -s %{_libdir}/libcurl.so.4 %{_libdir}/libcurl-gnutls.so.4
fi

%postun

%desktop_database_postun

%clean

%files
%defattr(-,root,root)
%dir %{_datadir}/spotify
%{_datadir}/spotify/*
%{_datadir}/applications/spotify.desktop
%{_datadir}/doc/${V_PKGNAME}/*
%{_bindir}/spotify
EOF
}


f_run_build() {
echo "Running rpm build"
if ! rpmbuild -bb --quiet --clean "${V_SPECS_DIR}"/spotify.spec; then
f_error "Spotify RPM failed to build. Aborting"
else
echo "Spotify RPM created in ${V_RPMS_DIR}/${V_RPM_ARCH}/"
fi
}


f_install_prompt() {
if [[ "${V_RUN_MODE}" != "prompt" ]]; then
  f_rpm_install
else
 while true
  do
   read -rp "Do you wish to install the Spotify RPM (y/n)?" Q_RPM_INSTALL

  case $Q_RPM_INSTALL in
  y ) f_rpm_install
   break;;

  n ) echo "OK not installing now"
   break;;

  esac
 done
fi
}


f_rpm_install() {
echo "Installing ${V_PKGNAME}-${V_DEB_VER}"
if ! sudo zypper --non-interactive --no-gpg-check in "${V_RPMS_DIR}"/"${V_RPM_ARCH}"/"${V_PKGNAME}"-"${V_DEB_VER}"*"${V_RPM_ARCH}".rpm; then
  f_error "Failed to install ${V_PKGNAME}-${V_DEB_VER}"
fi
}


f_create_repo() {
if ! rpm -q createrepo_c > /dev/null 2>&1; then
 echo "Installing CreateRepo for local filesystem repo"
 if ! sudo zypper --non-interactive in createrepo_c; then
 f_error "Failed to install createrepo. Aborting"
 fi
fi
if [[ ! -d "${V_LOCAL_REPO}" ]]; then
 echo "Creating local filesystem repo at ${V_LOCAL_REPO}"
 if ! sudo mkdir -p ${V_LOCAL_REPO}; then
  f_error "Failed to create local filesystem repo at ${V_LOCAL_REPO}. Aborting"
 fi
fi
if ! sudo find ${V_LOCAL_REPO} -type d -exec chmod 777 {} \+; then
 f_error "Failed to chmod ${V_LOCAL_REPO}"
fi
if ! sudo find ${V_LOCAL_REPO} -type f -exec chmod 666 {} \+; then
 f_error "Failed to chmod ${V_LOCAL_REPO}"
fi
f_update_local_repo
if [[ ! -f /etc/zypp/repos.d/${V_PRG_NAME}.repo ]]; then
 echo "Adding local file system repository to zypper"
 if ! sudo zypper ar -G --refresh "${V_LOCAL_REPO}" "${V_PRG_NAME}"; then
  f_error "Failed to add local repo to zypper. Aborting"
 fi
fi
}

f_create_systemd_unit() {
if [[ ! -f "${SYSTEMD_TIMER}" ]]; then
 echo "Creating automated Spotify builds"
 mkdir -p "${SYSTEMD_UNIT_DIR}"
 cat << EOF > "${SYSTEMD_UNIT}"
[Unit]                                                                                                                             
Description=${V_PRG_NAME} script                                                                                                                                                                         
                                                                                                                                                                                                              
[Service]                                                                                                                                                                
ExecStart=/usr/bin/${V_PRG_NAME} --scheduled

EOF
 cat << EOF > "${SYSTEMD_TIMER}"
[Unit]
Description=${V_PRG_NAME} timer

[Timer]
OnBootSec=5min
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
EOF
  sed -i "s/\(PREF_PROMPT_SCHEDULE=\)\(.*\)/\1YES/" "${V_CONFIG_FILE}"
fi
systemctl --user daemon-reload
systemctl --user disable "${V_PRG_NAME}"
systemctl --user enable "${V_PRG_NAME}.timer"
}


f_update_local_repo() {
if [[ "${V_RUN_MODE}" != "clean-repo" ]]; then
echo "Moving RPMs from your rpmbuild ${V_RPMS_DIR} to your local repo ${V_LOCAL_REPO}"
find "${V_RPMS_DIR}"/"${V_RPM_ARCH}"/ -name "${V_PKGNAME}"-*"${V_RPM_ARCH}".rpm -type f -exec mv -t "${V_LOCAL_REPO}" {} \+
fi
if ! createrepo -q "${V_LOCAL_REPO}"; then
 f_error "Failed to create / update local repo. Aborting"
fi
}

f_clean_repo() {
sudo find "${V_LOCAL_REPO}" -type f -name "*.rpm" -exec rm {} \;
f_update_local_repo
echo "done!"
}


f_main() {
while [ "$1" != "" ]; do
  case "$1" in
    -h | --help )       V_RUN_MODE="help"
                        f_logo
                        f_help
                        exit 0
                        ;;
    --quiet )           V_RUN_MODE="quiet"
                        f_logo
                        f_install_build_deps
                        f_create_rpmbuild_dirs
                        f_set_deb_ver
                        f_ver_compare
                        f_download
                        f_extract_deb
                        f_prepare_src
                        f_rpm_spec
                        f_run_build
                        f_install_prompt
                        f_create_repo
                        f_create_systemd_unit
                        f_script_location_check
                        break
                        ;;
    --scheduled | -scheduled )  V_RUN_MODE="scheduled"
                        f_set_deb_ver
                        f_ver_compare
                        f_download
                        f_extract_deb
                        f_prepare_src
                        f_rpm_spec
                        f_run_build
                        f_update_local_repo
                        break
                        ;;
    --create-schedule ) V_RUN_MODE="create-schedule"
                        f_logo
                        f_schedule_prompt
                        break
                        ;;
    --remove-schedule ) V_RUN_MODE="remove-schedule"
                        f_logo
                        f_remove_schedule
                        f_remove_repo
                        break
                        ;;
    --clean-repo )      V_RUN_MODE="clean-repo"
                        f_logo
                        f_clean_repo
                        break
                        ;;
    * )                 V_RUN_MODE="invalid"
                        f_logo
                        echo "Unrecognised option. Run --help for more info"
                        exit 1
    esac
    shift
done
if [[ -z "${V_RUN_MODE}" ]]; then
V_RUN_MODE="prompt"
 f_logo
 f_install_build_deps
 f_create_rpmbuild_dirs
 f_set_deb_ver
 f_ver_compare
 f_download
 f_extract_deb
 f_prepare_src
 f_rpm_spec
 f_run_build
 f_install_prompt
 f_schedule_prompt
fi
}


### EXECUTION BEGINS ###


f_root_check
f_arch_check
f_config
f_cleanup
f_main "$@"
f_cleanup
