gen-static-tv-lawn.py - tv-lawn - Bitreich TV Lawn
 (HTM) git clone git://bitreich.org/tv-lawn git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/tv-lawn
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       gen-static-tv-lawn.py (4823B)
       ---
            1 #!/usr/bin/env python
            2 # coding=utf-8
            3 #
            4 # © 2025 Christoph Lohmann <20h@r-36.net>
            5 #
            6 # This file is published under the terms of the GPLv3.
            7 #
            8 
            9 import os
           10 import sys
           11 import getopt
           12 import json
           13 import random
           14 
           15 def usage(app):
           16         app = os.path.basename(app)
           17         print("usage: %s [-h] [-b tv-garden-channel/]" % (app), file=sys.stderr)
           18         sys.exit(1)
           19 
           20 def main(args):
           21         try:
           22                 opts, largs = getopt.getopt(args[1:], "hb:")
           23         except getopt.GetoptError as err:
           24                 print(str(err))
           25                 usage(args[0])
           26 
           27         basedir = "tv-garden-channel-list"
           28         for o, a in opts:
           29                 if o == "-h":
           30                         usage(args[0])
           31                 elif o == "-b":
           32                         basedir = a
           33                 else:
           34                         assert False, "unhandled option"
           35 
           36         workdir = "%s/channels/raw" % (basedir)
           37         categoriesdir = "%s/categories" % (workdir)
           38         countriesdir = "%s/countries" % (workdir)
           39         countriesmd = "%s/countries_metadata.json" % (workdir)
           40 
           41         # Parse countries_metadata.json.
           42         with open(countriesmd, "r") as countriesfd:
           43                 countries = json.load(countriesfd)
           44         # Convert countries_metadata.json to lower case entries.
           45         countries = dict((k.lower(), v) for k,v in countries.items())
           46 
           47         # Get all files in countries/.
           48         (_, _, countryfiles) = list(os.walk(countriesdir))[0]
           49         # Add tv channels to the countries.
           50         for countryfile in countryfiles:
           51                 countryshort = countryfile.split(".", 1)[0].lower()
           52                 with open("%s/%s" % (countriesdir, countryfile), "r") as countryfd:
           53                         countrychannels = json.load(countryfd)
           54                         countries[countryshort]["channels"] = countrychannels
           55 
           56         categories = {}
           57         # Get all files in categories/.
           58         (_, _, categoryfiles) = list(os.walk(categoriesdir))[0]
           59         # Add tv channels to the categories.
           60         for categoryfile in categoryfiles:
           61                 categoryshort = categoryfile.split(".", 1)[0].lower()
           62                 with open("%s/%s" % (categoriesdir, categoryfile), "r") as categoryfd:
           63                         categorychannels = json.load(categoryfd)
           64                         categories[categoryshort] = {}
           65                         categories[categoryshort]["channels"] = categorychannels
           66 
           67         # Create big list of all channels.
           68         allchannels = {}
           69         for country in countries.keys():
           70                 if not "channels" in countries[country]:
           71                         continue
           72                 channels = countries[country]["channels"]
           73                 for channel in channels:
           74                         if "nanoid" in channel:
           75                                 allchannels[channel["nanoid"]] = channel
           76         # Do this after anything else, so category is set.
           77         for category in categories.keys():
           78                 channels = categories[category]["channels"]
           79                 for channel in channels:
           80                         if not "category" in channel:
           81                                 channel["category"] = []
           82                         channel["category"].append(category)
           83                         if "nanoid" in channel:
           84                                 allchannels[channel["nanoid"]] = channel
           85         # Set the random directory entries.
           86         randomchannels = random.choices(list(allchannels.keys()), k=12)
           87         i = 0
           88         for channel in randomchannels:
           89                 allchannels[channel]["random"] = "%d" % (i)
           90                 i += 1
           91 
           92         def write_channel_info(filename, channel):
           93                 if os.path.exists(filename):
           94                         os.remove(filename)
           95                 with open(filename, "w") as fd:
           96                         for direntry in ["name", "language", "isGeoBlocked", "nanoid", "category"]:
           97                                 fd.write("%s: %s\n" % (direntry, channel[direntry]))
           98                         if "country" in channel:
           99                                 country = countries[channel["country"]]
          100                                 for e in ["country", "timeZone"]:
          101                                         fd.write("%s: %s\n" % (e, country[e]))
          102                         for iptvurl in channel["iptv_urls"]:
          103                                 fd.write("[h|%s|URL:%s|server|port]\n" % (iptvurl, iptvurl))
          104                         for yturl in channel["youtube_urls"]:
          105                                 fd.write("[h|%s|URL:%s|server|port]\n" % (yturl, yturl))
          106 
          107         # Clean filenames for file hierarchy.
          108         def clean_filename(filename):
          109                 for c in ["/", " ", "|"]:
          110                         filename = filename.replace(c, "_")
          111                 return filename
          112 
          113         # Replace | in gph with \|.
          114         def clean_gphentry(entry):
          115                 for c in ["|"]:
          116                         entry = entry.replace(c, "\\|")
          117                 return entry
          118 
          119         # Raw dirs.
          120         for direntry in ["nanoid"]:
          121                 if not os.path.exists(direntry):
          122                         os.mkdir(direntry)
          123                 for channel in allchannels.keys():
          124                         c = allchannels[channel]
          125                         if direntry in c:
          126                                 write_channel_info("%s/%s.gph" % \
          127                                         (direntry, clean_filename(c[direntry])), c)
          128 
          129         # Symlink dirs.
          130         linkto = "nanoid"
          131         for direntry in ["language", "country", "name", "category", "random"]:
          132                 if not os.path.exists(direntry):
          133                         os.mkdir(direntry)
          134                 # Cleanup all directories.
          135                 (_, _, dirfiles) = list(os.walk(direntry))[0]
          136                 for f in dirfiles:
          137                         os.remove("%s/%s" % (direntry, f))
          138                 for channel in allchannels.keys():
          139                         c = allchannels[channel]
          140                         if direntry in c:
          141                                 if isinstance(c[direntry], list):
          142                                         direntries = c[direntry]
          143                                 else:
          144                                         direntries = [c[direntry]]
          145                                 for d in direntries:
          146                                         filename = "%s/%s.gph" % (direntry, clean_filename(d))
          147                                         if not os.path.exists(filename):
          148                                                 with open(filename, "w") as fd:
          149                                                         fd.write("== %s/%s ==\n" % (direntry, d))
          150                                         with open(filename, "a") as fd:
          151                                                 fd.write("[1|%s|../nanoid/%s.gph|server|port]\n" \
          152                                                         % (clean_gphentry(c["name"]), c["nanoid"]))
          153 
          154 
          155 
          156         return 0
          157 
          158 if __name__ == "__main__":
          159         sys.exit(main(sys.argv))
          160