Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@ debian/*debhelper*
debian/files
debian/hypnotix.substvars
usr/share/locale
usr/share/hypnotix/hypnotix.ui~
usr/share/hypnotix/hypnotix.ui~
.venv
.vscode
usr/share/data
usr/lib/hypnotix/__pycache__
usr/share/glib-2.0/schemas/*.compiled
120 changes: 93 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,112 @@
# Hypnotix
![build](https://github.com/linuxmint/hypnotix/actions/workflows/build.yml/badge.svg)
# Hypnotix for Windows

Hypnotix is an IPTV streaming application with support for live TV, movies and series.
Hypnotix for Windows is an IPTV streaming application with support for live TV.

![shadow](https://user-images.githubusercontent.com/1138515/99553152-b8bac780-29b5-11eb-9d75-8756ed7581b6.png)
It is a fork of [hypnotix](https://github.com/linuxmint/hypnotix) which is a Linux only app built and maintained for Linux Mint. It is built with GTK3 and my aim is to port this over to Windows with as minimal changes as required and future compatibility in mind.

It can support multiple IPTV providers of the following types:
I have only an initial build running in the crudest way possible and I have plans to bring this up to spec and also make it package/ship ready in future. For now, you will need to build the app on your own for now with the instructions below.

- M3U URL
- Xtream API
- Local M3U playlist
**Known Issues:**
- Live TV video overlay controls are not available. This is potentially a libmpv issue. See [this issue in python-mpv](https://github.com/jaseg/python-mpv/issues/103) for details.
- Movie and Series modules are not tested and are not a priority.
- There could be other issues

![shadow](https://github.com/user-attachments/assets/9735d7a2-7867-48c4-aa80-8b024c8488d8)

# License

- Code: GPLv3
- Flags: https://github.com/linuxmint/flags
- Icons on the landing page: CC BY-ND 2.0

# Requirements
# Development Requirements

- [MSYS2](https://github.com/msys2) (tested with UCRT64 profile)
- MSYS2 packages

> Note 1: Not all packages might be required and there might be duplicates. I need to test this in a fresh VM to find only the essential ones later.

> Note 2: Install the packages as ```pacman -S <packagename>``` in MSYS2

GTK
- mingw-w64-x86_64-gtk3
- mingw-w64-x86_64-glib2
- mingw-w64-x86_64-glade
- mingw-w64-x86_64-gstreamer

MPV
- mingw-w64-x86_64-mpv
- ucrt64/mingw-w64-ucrt-x86_64-mpv

GCC and Build
- mingw-w64-x86_64-gcc
- mingw-w64-x86_64-make
- mingw-w64-x86_64-pkg-config

Python
- mingw-w64-x86_64-python3
- mingw-w64-x86_64-python3-gobject
- mingw-w64-x86_64-python-pip

XML
- mingw-w64-x86_64-libxml2
- mingw-w64-x86_64-libxslt

Adwaita Theme for icons
- mingw64/mingw-w64-x86_64-adwaita-icon-theme
- ucrt64/mingw-w64-ucrt-x86_64-adwaita-icon-theme


# Run Steps:

1) Install MSYS2 and git clone repo.
> **Note:** Use Windows Terminal (with MSYS2/UCRT64 shell profile) or MSYS2 app directly or whichever terminal app you are comfortable with for shell access.
```git clone git@github.com:lakshminarayananb/hypnotix-windows.git```

2) Install the above mentioned development packages.
```
pacman -S mingw-w64-x86_64-gtk3
pacman -S mingw-w64-x86_64-glade
pacman -S mingw-w64-x86_64-glib2
pacman -S mingw-w64-x86_64-gstreamer

pacman -S mingw-w64-x86_64-mpv
pacman -S ucrt64/mingw-w64-ucrt-x86_64-mpv

pacman -S mingw-w64-x86_64-gcc
pacman -S mingw-w64-x86_64-make
pacman -S mingw-w64-x86_64-pkg-config

pacman -S mingw-w64-x86_64-python3
pacman -S mingw-w64-x86_64-python3-gobject
pacman -S mingw-w64-x86_64-python-pip

pacman -S mingw-w64-x86_64-libxml2
pacman -S mingw-w64-x86_64-libxslt

pacman -S ucrt64/mingw-w64-ucrt-x86_64-adwaita-icon-theme
pacman -S mingw64/mingw-w64-x86_64-adwaita-icon-theme
```

3) Install python dependencies (you may try with venv)
```
pip install mpv
pip install requests
pip install setproctitle
pip install unidecode
```
> **Note:** ```pip install IMDbPY``` is removed for now due to build issues and related features are commented out.

4) Now running the hypnotix.py should launch the app
```python3 usr/lib/hypnotix/hypnotix.py```

- libxapp 2.6+
- libmpv
- python3-imdbpy (for Older Mint and Debian releases get it from https://packages.ubuntu.com/focal/all/python3-imdbpy/download)
- circle-flags (https://github.com/linuxmint/circle-flags)

# TV Channels and media content

Hypnotix does not provide content or TV channels, it is a player application which streams from IPTV providers.
Hypnotix for Windows or Hypnotix does not provide content or TV channels, it is a player application which streams from IPTV providers.

By default, Hypnotix is configured with one IPTV provider called Free-TV: https://github.com/Free-TV/IPTV.
By default, Hypnotix for Windows is configured with an IPTV provider called Free-TV: https://github.com/Free-TV/IPTV.

This provider was chosen because it satisfied the following criterias:

Check failure on line 109 in README.md

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

criterias ==> criteria

- It only includes free, legal, publicly available content
- It groups TV channels by countries
Expand All @@ -38,14 +114,4 @@

Issues relating to TV channels and media content should be addressed directly to the relevant provider.

Note: Feel free to remove Free-TV from Hypnotix if you don't use it, or add any other provider you may have access to or local M3U playlists.

# Wayland compatibility

If you're using Wayland go the Hypnotix preferences and add the following to the list of MPV options:

`vo=x11`

Run Hypnotix with:

`GDK_BACKEND=x11 hypnotix`
Note: Feel free to remove Free-TV from Hypnotix if you don't use it, or add any other provider you may have access to or local M3U playlists.
26 changes: 18 additions & 8 deletions usr/lib/hypnotix/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
EXTINF = re.compile(r'^#EXTINF:(?P<duration>-?\d+?) ?(?P<params>.*),(?P<title>.*?)$')
SERIES = re.compile(r"(?P<series>.*?) S(?P<season>.\d{1,2}).*E(?P<episode>.\d{1,2}.*)$", re.IGNORECASE)

PROVIDERS_PATH = os.path.join(GLib.get_user_cache_dir(), "hypnotix", "providers")
PROVIDERS_PATH = os.path.normpath(os.path.join(GLib.get_user_cache_dir(), "hypnotix", "providers"))

TV_GROUP, MOVIES_GROUP, SERIES_GROUP = range(3)
# print("PROVIDERS_PATH:", PROVIDERS_PATH)

FAVORITES_PATH = os.path.join(GLib.get_user_cache_dir(), "hypnotix", "favorites", "list")
FAVORITES_PATH = os.path.normpath(os.path.join(GLib.get_user_cache_dir(), "hypnotix", "favorites", "list"))
#print("FAVORITES_PATH:", FAVORITES_PATH)

# Used as a decorator to run things in the background
def async_function(func):
Expand Down Expand Up @@ -50,7 +52,7 @@
self.name, self.type_id, self.url, self.username, self.password, self.epg = provider_info.split(":::")
else:
self.name = name
self.path = os.path.join(PROVIDERS_PATH, slugify(self.name))
self.path = os.path.normpath(os.path.join(PROVIDERS_PATH, slugify(self.name)))
self.groups = []
self.channels = []
self.movies = []
Expand All @@ -73,7 +75,7 @@
self.series = []


class Serie:

Check failure on line 78 in usr/lib/hypnotix/common.py

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

Serie ==> Series
def __init__(self, name):
self.name = name
self.logo = None
Expand Down Expand Up @@ -129,11 +131,13 @@
provider_name = "favorites"
else:
provider_name = provider.name
self.logo_path = os.path.join(PROVIDERS_PATH, "%s-%s%s" % (slugify(provider_name), slugify(self.name), ext))
self.logo_path = os.path.normpath(os.path.join(PROVIDERS_PATH, "%s-%s%s" % (slugify(provider_name), slugify(self.name), ext)))

class Manager:
def __init__(self, settings):
os.system("mkdir -p '%s'" % PROVIDERS_PATH)
#os.system("mkdir -p '%s'" % PROVIDERS_PATH)
os.makedirs(PROVIDERS_PATH, exist_ok=True) #Windows - create providers directory if not exists
os.makedirs(os.path.dirname(FAVORITES_PATH), exist_ok=True) #Windows - create favorites directory if not exist
self.verbose = False
self.settings = settings

Expand Down Expand Up @@ -196,7 +200,7 @@
print("The file size is incorrect, deleting")
os.remove(provider.path)
else:
# Set the datatime when it was last retreived

Check failure on line 203 in usr/lib/hypnotix/common.py

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

retreived ==> retrieved
# self.settings.set_
ret_code = True
else:
Expand Down Expand Up @@ -250,17 +254,17 @@
channel.url = line
self.debug(" --> URL found: ", line)

serie = None

Check failure on line 257 in usr/lib/hypnotix/common.py

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

serie ==> series
f = SERIES.fullmatch(channel.name)
if f is not None:
res = f.groupdict()
series_name = res['series']
if series_name in series.keys():
serie = series[series_name]

Check failure on line 263 in usr/lib/hypnotix/common.py

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

serie ==> series
else:
serie = Serie(series_name)

Check failure on line 265 in usr/lib/hypnotix/common.py

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

Serie ==> Series

Check failure on line 265 in usr/lib/hypnotix/common.py

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

serie ==> series
# todo put in group
provider.series.append(serie)

Check failure on line 267 in usr/lib/hypnotix/common.py

View workflow job for this annotation

GitHub Actions / build / build (mint22, linuxmintd/mint22-amd64, Mint 22, true) / Mint 22

serie ==> series
series[series_name] = serie
serie.logo = channel.logo
serie.logo_path = channel.logo_path
Expand Down Expand Up @@ -295,9 +299,15 @@

def load_favorites(self):
favorites = []
with open(FAVORITES_PATH, 'r', encoding="utf-8", errors="ignore") as f:
for line in f:
favorites.append(line.strip())
try:
with open(FAVORITES_PATH, 'r', encoding="utf-8", errors="ignore") as f:
for line in f:
favorites.append(line.strip())
except FileNotFoundError:
# Create favorites directory and new listfile if not exists
os.makedirs(os.path.dirname(FAVORITES_PATH), exist_ok=True)
with open(FAVORITES_PATH, 'w', encoding="utf-8") as f:
pass # Create empty file
return favorites

def save_favorites(self, favorites):
Expand Down
Loading
Loading