Initial commit
This commit is contained in:
commit
0c9cc7f5fc
9 changed files with 1308 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.m3u
|
||||||
|
node_modules
|
22
config/categories.json
Normal file
22
config/categories.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
[
|
||||||
|
"auto",
|
||||||
|
"animation",
|
||||||
|
"business",
|
||||||
|
"classic",
|
||||||
|
"comedy",
|
||||||
|
"cooking",
|
||||||
|
"culture",
|
||||||
|
"documentary",
|
||||||
|
"education",
|
||||||
|
"entertainment",
|
||||||
|
"family",
|
||||||
|
"general",
|
||||||
|
"kids",
|
||||||
|
"lifestyle",
|
||||||
|
"movies",
|
||||||
|
"news",
|
||||||
|
"outdoor",
|
||||||
|
"series",
|
||||||
|
"science",
|
||||||
|
"sports"
|
||||||
|
]
|
4
config/countries.json
Normal file
4
config/countries.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[
|
||||||
|
"CA",
|
||||||
|
"US"
|
||||||
|
]
|
3
config/languages.json
Normal file
3
config/languages.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[
|
||||||
|
"eng"
|
||||||
|
]
|
96
iptv-m3u-update
Executable file
96
iptv-m3u-update
Executable file
|
@ -0,0 +1,96 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
deps=('curl' 'dos2unix' 'grep' 'node' 'rows' 'sqlite3')
|
||||||
|
|
||||||
|
# URLs
|
||||||
|
tmp_m3u_url='https://iptv-org.github.io/iptv/index.m3u'
|
||||||
|
tmp_csv_url='https://raw.githubusercontent.com/iptv-org/database/master/data/channels.csv'
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp_m3u_file='/tmp/iptv.m3u'
|
||||||
|
tmp_csv_file='/tmp/iptv.csv'
|
||||||
|
tmp_processed_csv_file='/tmp/iptv-processed.csv'
|
||||||
|
tmp_sqlite_file='/tmp/iptv.sqlite'
|
||||||
|
|
||||||
|
# Final m3u
|
||||||
|
final_m3u='channels.m3u'
|
||||||
|
|
||||||
|
function cleanup {
|
||||||
|
[[ -f "$tmp_m3u_file" ]] && rm "$tmp_m3u_file"
|
||||||
|
[[ -f "$tmp_csv_file" ]] && rm "$tmp_csv_file"
|
||||||
|
[[ -f "$tmp_processed_csv_file" ]] && rm "$tmp_processed_csv_file"
|
||||||
|
[[ -f "$tmp_sqlite_file" ]] && rm "$tmp_sqlite_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup_and_exit {
|
||||||
|
cleanup
|
||||||
|
exit "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
function update {
|
||||||
|
# Ensure old temporary files don't exist
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
if ! curl -s "$tmp_m3u_url" > "$tmp_m3u_file"; then
|
||||||
|
printf '%s\n' "Unable to download $tmp_m3u_url"
|
||||||
|
cleanup_and_exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if curl -s "$tmp_csv_url" > "$tmp_csv_file"; then
|
||||||
|
# Convert to unix format
|
||||||
|
dos2unix "$tmp_csv_file"
|
||||||
|
|
||||||
|
# Add links to each channel
|
||||||
|
while read -r; do
|
||||||
|
if [[ "$REPLY" =~ ^([^,]*), ]]; then
|
||||||
|
id="${BASH_REMATCH[1]}"
|
||||||
|
|
||||||
|
if [[ "$id" = 'id' ]]; then
|
||||||
|
printf '%s\n' "${REPLY},link"
|
||||||
|
else
|
||||||
|
match="$(grep -A1 'tvg-id="'"$id"'"' "$tmp_m3u_file")"
|
||||||
|
|
||||||
|
if (( $? == 0 )); then
|
||||||
|
link="$(grep -e '^http' <<< "$match")"
|
||||||
|
printf '%s\n' "$REPLY,$link"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$tmp_csv_file" > "$tmp_processed_csv_file"
|
||||||
|
|
||||||
|
# Convert to sqlite
|
||||||
|
rows csv2sqlite "$tmp_processed_csv_file" "$tmp_sqlite_file"
|
||||||
|
|
||||||
|
# Create the m3u
|
||||||
|
./scripts/iptv-generate-m3u > "$final_m3u"
|
||||||
|
|
||||||
|
# Delete temporary files
|
||||||
|
cleanup_and_exit 0
|
||||||
|
else
|
||||||
|
printf '%s\n' "Unable to download $tmp_csv_url"
|
||||||
|
cleanup_and_exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for missing dependencies
|
||||||
|
declare -a missing_deps=()
|
||||||
|
|
||||||
|
for dep in "${deps[@]}"; do
|
||||||
|
type -P "$dep" >/dev/null \
|
||||||
|
|| missing_deps=( "${missing_deps[@]}" "$dep" )
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -n "${missing_deps[*]}" ]] && {
|
||||||
|
printf '%s\n' "missing dependencies ($(
|
||||||
|
for (( x=0; x < ${#missing_deps[@]}; x++ )); do
|
||||||
|
printf '%s' "${missing_deps[$x]}"
|
||||||
|
(( ( x + 1 ) < ${#missing_deps[@]} )) && printf '%s' ', '
|
||||||
|
done
|
||||||
|
))"
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update M3U
|
||||||
|
update
|
1115
package-lock.json
generated
Normal file
1115
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
5
package.json
Normal file
5
package.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"sqlite3": "^5.1.4"
|
||||||
|
}
|
||||||
|
}
|
19
readme.md
Normal file
19
readme.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# IPTV M3U
|
||||||
|
|
||||||
|
Takes [iptv-org](https://github.com/iptv-org) data and creates a custom m3u
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
* curl: https://curl.haxx.se/
|
||||||
|
* dos2unix: https://waterlan.home.xs4all.nl/dos2unix.html
|
||||||
|
* grep: https://www.gnu.org/software/grep/
|
||||||
|
* node/npm: https://nodejs.org/en/
|
||||||
|
* rows[cli]: http://turicas.info/rows/cli/
|
||||||
|
* sqlite3: https://www.sqlite.org
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Customize the languages, countries and categories in the respective json files in the `config` folder using the ids from the respective csv here: https://github.com/iptv-org/database/blob/master/data
|
||||||
|
2. Run `npm install`
|
||||||
|
3. Run `./iptv-m3u-update`
|
||||||
|
4. Load your freshly generated `channels.m3u`
|
42
scripts/iptv-generate-m3u
Executable file
42
scripts/iptv-generate-m3u
Executable file
|
@ -0,0 +1,42 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const sqlite3 = require("sqlite3").verbose(),
|
||||||
|
db = new sqlite3.Database("/tmp/iptv.sqlite"),
|
||||||
|
languages = require("../config/languages.json"),
|
||||||
|
countries = require("../config/countries.json"),
|
||||||
|
categories = require("../config/categories.json");
|
||||||
|
|
||||||
|
let languageMatch = "",
|
||||||
|
countryMatch = "",
|
||||||
|
categoryMatch = "";
|
||||||
|
|
||||||
|
languages.forEach((language, index) => {
|
||||||
|
languageMatch += `languages='${language}'`;
|
||||||
|
|
||||||
|
if (index < languages.length - 1) {
|
||||||
|
languageMatch += " OR ";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
countries.forEach((country, index) => {
|
||||||
|
countryMatch += `country='${country}'`;
|
||||||
|
|
||||||
|
if (index < countries.length - 1) {
|
||||||
|
countryMatch += " OR ";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
categories.forEach((category, index) => {
|
||||||
|
categoryMatch += `categories LIKE '%${category}%'`;
|
||||||
|
|
||||||
|
if (index < categories.length - 1) {
|
||||||
|
categoryMatch += " OR ";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
db.serialize(() => {
|
||||||
|
db.each(`SELECT * FROM iptv_processed WHERE is_nsfw='FALSE' AND (${languageMatch}) AND link NOT LIKE '' AND (${countryMatch}) AND (${categoryMatch})`, (err, row) => {
|
||||||
|
console.log(`#EXTINF:-1 tvg-id="${row.id}" tvg-logo="${row.logo}" group-title="${row.name}"`);
|
||||||
|
console.log(row.link);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue