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