mirror of
https://github.com/iptv-org/database.git
synced 2024-12-03 07:39:34 -05:00
Init
This commit is contained in:
commit
26d5bf0436
27 changed files with 43517 additions and 0 deletions
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: iptv-org
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
19
.github/workflows/check.yml
vendored
Normal file
19
.github/workflows/check.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
name: check
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- id: files
|
||||
uses: tj-actions/changed-files@v12.2
|
||||
with:
|
||||
files: \.csv$
|
||||
- name: validate
|
||||
if: steps.files.outputs.any_changed == 'true'
|
||||
run: |
|
||||
npm install
|
||||
npm run db:validate -- ${{ steps.files.outputs.all_changed_files }}
|
29
.github/workflows/deploy.yml
vendored
Normal file
29
.github/workflows/deploy.yml
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
name: deploy
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npm install
|
||||
- run: npm run db:export
|
||||
- uses: tibdex/github-app-token@v1
|
||||
if: ${{ !env.ACT }}
|
||||
id: create-app-token
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
- uses: JamesIves/github-pages-deploy-action@4.1.1
|
||||
if: ${{ !env.ACT }}
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: .gh-pages
|
||||
token: ${{ steps.create-app-token.outputs.token }}
|
||||
git-config-name: iptv-bot[bot]
|
||||
git-config-email: 84861620+iptv-bot[bot]@users.noreply.github.com
|
||||
commit-message: '[Bot] Deploy to GitHub Pages'
|
||||
clean: false
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/node_modules/
|
||||
/.artifacts/
|
24
LICENSE
Normal file
24
LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
29
data/categories.csv
Normal file
29
data/categories.csv
Normal file
|
@ -0,0 +1,29 @@
|
|||
id,name
|
||||
auto,Auto
|
||||
animation,Animation
|
||||
business,Business
|
||||
classic,Classic
|
||||
comedy,Comedy
|
||||
cooking,Cooking
|
||||
culture,Culture
|
||||
documentary,Documentary
|
||||
education,Education
|
||||
entertainment,Entertainment
|
||||
family,Family
|
||||
general,General
|
||||
kids,Kids
|
||||
legislative,Legislative
|
||||
lifestyle,Lifestyle
|
||||
movies,Movies
|
||||
music,Music
|
||||
news,News
|
||||
outdoor,Outdoor
|
||||
relax,Relax
|
||||
religious,Religious
|
||||
series,Series
|
||||
science,Science
|
||||
shop,Shop
|
||||
sports,Sports
|
||||
travel,Travel
|
||||
weather,Weather
|
||||
xxx,XXX
|
|
29797
data/channels.csv
Normal file
29797
data/channels.csv
Normal file
File diff suppressed because it is too large
Load diff
251
data/countries.csv
Normal file
251
data/countries.csv
Normal file
|
@ -0,0 +1,251 @@
|
|||
name,code,lang,flag
|
||||
Afghanistan,AF,pus,🇦🇫
|
||||
Albania,AL,sqi,🇦🇱
|
||||
Algeria,DZ,ara,🇩🇿
|
||||
American Samoa,AS,eng,🇦🇸
|
||||
Andorra,AD,cat,🇦🇩
|
||||
Angola,AO,por,🇦🇴
|
||||
Anguilla,AI,eng,🇦🇮
|
||||
Antarctica,AQ,eng,🇦🇶
|
||||
Antigua and Barbuda,AG,eng,🇦🇬
|
||||
Argentina,AR,spa,🇦🇷
|
||||
Armenia,AM,hye,🇦🇲
|
||||
Aruba,AW,nld,🇦🇼
|
||||
Australia,AU,eng,🇦🇺
|
||||
Austria,AT,deu,🇦🇹
|
||||
Azerbaijan,AZ,aze,🇦🇿
|
||||
Bahamas,BS,eng,🇧🇸
|
||||
Bahrain,BH,ara,🇧🇭
|
||||
Bangladesh,BD,ben,🇧🇩
|
||||
Barbados,BB,eng,🇧🇧
|
||||
Belarus,BY,bel,🇧🇾
|
||||
Belgium,BE,nld,🇧🇪
|
||||
Belize,BZ,eng,🇧🇿
|
||||
Benin,BJ,fra,🇧🇯
|
||||
Bermuda,BM,eng,🇧🇲
|
||||
Bhutan,BT,dzo,🇧🇹
|
||||
Bolivia,BO,spa,🇧🇴
|
||||
Bonaire,BQ,nld,🇧🇶
|
||||
Bosnia and Herzegovina,BA,bos,🇧🇦
|
||||
Botswana,BW,eng,🇧🇼
|
||||
Bouvet Island,BV,nor,🇧🇻
|
||||
Brazil,BR,por,🇧🇷
|
||||
British Indian Ocean Territory,IO,eng,🇮🇴
|
||||
British Virgin Islands,VG,eng,🇻🇬
|
||||
Brunei,BN,msa,🇧🇳
|
||||
Bulgaria,BG,bul,🇧🇬
|
||||
Burkina Faso,BF,fra,🇧🇫
|
||||
Burundi,BI,fra,🇧🇮
|
||||
Cambodia,KH,khm,🇰🇭
|
||||
Cameroon,CM,eng,🇨🇲
|
||||
Canada,CA,eng,🇨🇦
|
||||
Cape Verde,CV,por,🇨🇻
|
||||
Cayman Islands,KY,eng,🇰🇾
|
||||
Central African Republic,CF,fra,🇨🇫
|
||||
Chad,TD,fra,🇹🇩
|
||||
Chile,CL,spa,🇨🇱
|
||||
China,CN,zho,🇨🇳
|
||||
Christmas Island,CX,eng,🇨🇽
|
||||
Cocos (Keeling) Islands,CC,eng,🇨🇨
|
||||
Colombia,CO,spa,🇨🇴
|
||||
Comoros,KM,ara,🇰🇲
|
||||
Cook Islands,CK,eng,🇨🇰
|
||||
Costa Rica,CR,spa,🇨🇷
|
||||
Croatia,HR,hrv,🇭🇷
|
||||
Cuba,CU,spa,🇨🇺
|
||||
Curacao,CW,nld,🇨🇼
|
||||
Cyprus,CY,ell,🇨🇾
|
||||
Czech Republic,CZ,ces,🇨🇿
|
||||
Democratic Republic of the Congo,CD,fra,🇨🇩
|
||||
Denmark,DK,dan,🇩🇰
|
||||
Djibouti,DJ,fra,🇩🇯
|
||||
Dominica,DM,eng,🇩🇲
|
||||
Dominican Republic,DO,spa,🇩🇴
|
||||
East Timor,TL,por,🇹🇱
|
||||
Ecuador,EC,spa,🇪🇨
|
||||
Egypt,EG,ara,🇪🇬
|
||||
El Salvador,SV,spa,🇸🇻
|
||||
Equatorial Guinea,GQ,spa,🇬🇶
|
||||
Eritrea,ER,tir,🇪🇷
|
||||
Estonia,EE,est,🇪🇪
|
||||
Ethiopia,ET,amh,🇪🇹
|
||||
Falkland Islands,FK,eng,🇫🇰
|
||||
Faroe Islands,FO,fao,🇫🇴
|
||||
Fiji,FJ,eng,🇫🇯
|
||||
Finland,FI,fin,🇫🇮
|
||||
France,FR,fra,🇫🇷
|
||||
French Guiana,GF,fra,🇬🇫
|
||||
French Polynesia,PF,fra,🇵🇫
|
||||
French Southern Territories,TF,fra,🇹🇫
|
||||
Gabon,GA,fra,🇬🇦
|
||||
Gambia,GM,eng,🇬🇲
|
||||
Georgia,GE,kat,🇬🇪
|
||||
Germany,DE,deu,🇩🇪
|
||||
Ghana,GH,eng,🇬🇭
|
||||
Gibraltar,GI,eng,🇬🇮
|
||||
Greece,GR,ell,🇬🇷
|
||||
Greenland,GL,kal,🇬🇱
|
||||
Grenada,GD,eng,🇬🇩
|
||||
Guadeloupe,GP,fra,🇬🇵
|
||||
Guam,GU,eng,🇬🇺
|
||||
Guatemala,GT,spa,🇬🇹
|
||||
Guernsey,GG,eng,🇬🇬
|
||||
Guinea,GN,fra,🇬🇳
|
||||
Guinea-Bissau,GW,por,🇬🇼
|
||||
Guyana,GY,eng,🇬🇾
|
||||
Haiti,HT,fra,🇭🇹
|
||||
Heard Island and McDonald Islands,HM,eng,🇭🇲
|
||||
Honduras,HN,spa,🇭🇳
|
||||
Hong Kong,HK,zho,🇭🇰
|
||||
Hungary,HU,hun,🇭🇺
|
||||
Iceland,IS,isl,🇮🇸
|
||||
India,IN,hin,🇮🇳
|
||||
Indonesia,ID,ind,🇮🇩
|
||||
Iran,IR,fas,🇮🇷
|
||||
Iraq,IQ,ara,🇮🇶
|
||||
Ireland,IE,gle,🇮🇪
|
||||
Isle of Man,IM,eng,🇮🇲
|
||||
Israel,IL,heb,🇮🇱
|
||||
Italy,IT,ita,🇮🇹
|
||||
Ivory Coast,CI,fra,🇨🇮
|
||||
Jamaica,JM,eng,🇯🇲
|
||||
Japan,JP,jpn,🇯🇵
|
||||
Jersey,JE,eng,🇯🇪
|
||||
Jordan,JO,ara,🇯🇴
|
||||
Kazakhstan,KZ,kaz,🇰🇿
|
||||
Kenya,KE,eng,🇰🇪
|
||||
Kiribati,KI,eng,🇰🇮
|
||||
Kosovo,XK,sqi,🇽🇰
|
||||
Kuwait,KW,ara,🇰🇼
|
||||
Kyrgyzstan,KG,kir,🇰🇬
|
||||
Laos,LA,lao,🇱🇦
|
||||
Latvia,LV,lav,🇱🇻
|
||||
Lebanon,LB,ara,🇱🇧
|
||||
Lesotho,LS,eng,🇱🇸
|
||||
Liberia,LR,eng,🇱🇷
|
||||
Libya,LY,ara,🇱🇾
|
||||
Liechtenstein,LI,deu,🇱🇮
|
||||
Lithuania,LT,lit,🇱🇹
|
||||
Luxembourg,LU,fra,🇱🇺
|
||||
Macao,MO,zho,🇲🇴
|
||||
Madagascar,MG,fra,🇲🇬
|
||||
Malawi,MW,eng,🇲🇼
|
||||
Malaysia,MY,msa,🇲🇾
|
||||
Maldives,MV,div,🇲🇻
|
||||
Mali,ML,fra,🇲🇱
|
||||
Malta,MT,mlt,🇲🇹
|
||||
Marshall Islands,MH,eng,🇲🇭
|
||||
Martinique,MQ,fra,🇲🇶
|
||||
Mauritania,MR,ara,🇲🇷
|
||||
Mauritius,MU,eng,🇲🇺
|
||||
Mayotte,YT,fra,🇾🇹
|
||||
Mexico,MX,spa,🇲🇽
|
||||
Micronesia,FM,eng,🇫🇲
|
||||
Moldova,MD,ron,🇲🇩
|
||||
Monaco,MC,fra,🇲🇨
|
||||
Mongolia,MN,mon,🇲🇳
|
||||
Montenegro,ME,srp,🇲🇪
|
||||
Montserrat,MS,eng,🇲🇸
|
||||
Morocco,MA,ara,🇲🇦
|
||||
Mozambique,MZ,por,🇲🇿
|
||||
Myanmar (Burma),MM,mya,🇲🇲
|
||||
Namibia,NA,eng,🇳🇦
|
||||
Nauru,NR,eng,🇳🇷
|
||||
Nepal,NP,nep,🇳🇵
|
||||
Netherlands,NL,nld,🇳🇱
|
||||
New Caledonia,NC,fra,🇳🇨
|
||||
New Zealand,NZ,eng,🇳🇿
|
||||
Nicaragua,NI,spa,🇳🇮
|
||||
Niger,NE,fra,🇳🇪
|
||||
Nigeria,NG,eng,🇳🇬
|
||||
Niue,NU,eng,🇳🇺
|
||||
Norfolk Island,NF,eng,🇳🇫
|
||||
North Korea,KP,kor,🇰🇵
|
||||
North Macedonia,MK,mkd,🇲🇰
|
||||
Northern Mariana Islands,MP,eng,🇲🇵
|
||||
Norway,NO,nor,🇳🇴
|
||||
Oman,OM,ara,🇴🇲
|
||||
Pakistan,PK,eng,🇵🇰
|
||||
Palau,PW,eng,🇵🇼
|
||||
Palestine,PS,ara,🇵🇸
|
||||
Panama,PA,spa,🇵🇦
|
||||
Papua New Guinea,PG,eng,🇵🇬
|
||||
Paraguay,PY,spa,🇵🇾
|
||||
Peru,PE,spa,🇵🇪
|
||||
Philippines,PH,eng,🇵🇭
|
||||
Pitcairn Islands,PN,eng,🇵🇳
|
||||
Poland,PL,pol,🇵🇱
|
||||
Portugal,PT,por,🇵🇹
|
||||
Puerto Rico,PR,spa,🇵🇷
|
||||
Qatar,QA,ara,🇶🇦
|
||||
Republic of the Congo,CG,fra,🇨🇬
|
||||
Romania,RO,ron,🇷🇴
|
||||
Russia,RU,rus,🇷🇺
|
||||
Rwanda,RW,kin,🇷🇼
|
||||
Réunion,RE,fra,🇷🇪
|
||||
Saint Barthélemy,BL,fra,🇧🇱
|
||||
Saint Helena,SH,eng,🇸🇭
|
||||
Saint Kitts and Nevis,KN,eng,🇰🇳
|
||||
Saint Lucia,LC,eng,🇱🇨
|
||||
Saint Martin,MF,eng,🇲🇫
|
||||
Saint Pierre and Miquelon,PM,fra,🇵🇲
|
||||
Saint Vincent and the Grenadines,VC,eng,🇻🇨
|
||||
Samoa,WS,smo,🇼🇸
|
||||
San Marino,SM,ita,🇸🇲
|
||||
Saudi Arabia,SA,ara,🇸🇦
|
||||
Senegal,SN,fra,🇸🇳
|
||||
Serbia,RS,srp,🇷🇸
|
||||
Seychelles,SC,fra,🇸🇨
|
||||
Sierra Leone,SL,eng,🇸🇱
|
||||
Singapore,SG,eng,🇸🇬
|
||||
Sint Maarten,SX,nld,🇸🇽
|
||||
Slovakia,SK,slk,🇸🇰
|
||||
Slovenia,SI,slv,🇸🇮
|
||||
Solomon Islands,SB,eng,🇸🇧
|
||||
Somalia,SO,som,🇸🇴
|
||||
South Africa,ZA,afr,🇿🇦
|
||||
South Georgia and the South Sandwich Islands,GS,eng,🇬🇸
|
||||
South Korea,KR,kor,🇰🇷
|
||||
South Sudan,SS,eng,🇸🇸
|
||||
Spain,ES,spa,🇪🇸
|
||||
Sri Lanka,LK,sin,🇱🇰
|
||||
Sudan,SD,ara,🇸🇩
|
||||
Suriname,SR,nld,🇸🇷
|
||||
Svalbard and Jan Mayen,SJ,nor,🇸🇯
|
||||
Swaziland,SZ,eng,🇸🇿
|
||||
Sweden,SE,swe,🇸🇪
|
||||
Switzerland,CH,deu,🇨🇭
|
||||
Syria,SY,ara,🇸🇾
|
||||
São Tomé and Príncipe,ST,por,🇸🇹
|
||||
Taiwan,TW,zho,🇹🇼
|
||||
Tajikistan,TJ,tgk,🇹🇯
|
||||
Tanzania,TZ,swa,🇹🇿
|
||||
Thailand,TH,tha,🇹🇭
|
||||
Togo,TG,fra,🇹🇬
|
||||
Tokelau,TK,eng,🇹🇰
|
||||
Tonga,TO,eng,🇹🇴
|
||||
Trinidad and Tobago,TT,eng,🇹🇹
|
||||
Tunisia,TN,ara,🇹🇳
|
||||
Turkey,TR,tur,🇹🇷
|
||||
Turkmenistan,TM,tuk,🇹🇲
|
||||
Turks and Caicos Islands,TC,eng,🇹🇨
|
||||
Tuvalu,TV,eng,🇹🇻
|
||||
U.S. Minor Outlying Islands,UM,eng,🇺🇲
|
||||
U.S. Virgin Islands,VI,eng,🇻🇮
|
||||
Uganda,UG,eng,🇺🇬
|
||||
Ukraine,UA,ukr,🇺🇦
|
||||
United Arab Emirates,AE,ara,🇦🇪
|
||||
United Kingdom,UK,eng,🇬🇧
|
||||
United States,US,eng,🇺🇸
|
||||
Uruguay,UY,spa,🇺🇾
|
||||
Uzbekistan,UZ,uzb,🇺🇿
|
||||
Vanuatu,VU,bis,🇻🇺
|
||||
Vatican City,VA,ita,🇻🇦
|
||||
Venezuela,VE,spa,🇻🇪
|
||||
Vietnam,VN,vie,🇻🇳
|
||||
Wallis and Futuna,WF,fra,🇼🇫
|
||||
Western Sahara,EH,spa,🇪🇭
|
||||
Yemen,YE,ara,🇾🇪
|
||||
Zambia,ZM,eng,🇿🇲
|
||||
Zimbabwe,ZW,eng,🇿🇼
|
||||
Åland,AX,swe,🇦🇽
|
|
7894
data/languages.csv
Normal file
7894
data/languages.csv
Normal file
File diff suppressed because it is too large
Load diff
25
data/regions.csv
Normal file
25
data/regions.csv
Normal file
|
@ -0,0 +1,25 @@
|
|||
name,code,countries
|
||||
Africa,AFR,AO;BF;BI;BJ;BW;CD;CF;CG;CI;CM;CV;DJ;DZ;EG;EH;ER;ET;GA;GH;GM;GN;GQ;GW;KE;KM;LR;LS;LY;MA;MG;ML;MR;MU;MW;MZ;NA;NE;NG;RE;RW;SC;SD;SH;SL;SN;SO;SS;ST;SZ;TD;TF;TG;TN;TZ;UG;YT;ZA;ZM;ZW
|
||||
Americas,AMER,AG;AI;AR;AW;BB;BL;BM;BO;BR;BS;BV;BZ;CA;CL;CO;CR;CU;CW;DM;DO;EC;FK;GD;GF;GL;GP;GS;GT;GY;HN;HT;JM;KN;KY;LC;MF;MQ;MS;MX;NI;PA;PE;PM;PR;PY;SR;SV;SX;TC;TT;US;UY;VC;VE;VG;VI
|
||||
Arab world,ARAB,AE;BH;DJ;DZ;EG;IQ;JO;KM;KW;LB;LY;MA;MR;OM;PS;QA;SA;SD;SO;SY;TN;YE
|
||||
Asia,ASIA,AE;AF;AM;AZ;BD;BH;BN;BT;CN;CY;GE;ID;IL;IN;IQ;IR;JO;JP;KG;KH;KP;KR;KW;KZ;LA;LB;LK;MM;MN;MV;MY;NP;OM;PH;PK;PS;QA;RU;SA;SG;SY;TH;TJ;TL;TM;TR;TW;UZ;VN;YE
|
||||
Asia-Pacific,APAC,AF;AS;AU;BD;BN;BT;CK;CN;FJ;FM;GU;ID;IN;JP;KH;KI;KP;KR;LA;LK;MH;MM;MN;MP;MV;MY;NC;NF;NP;NR;NU;NZ;PF;PG;PH;PK;PN;PW;SB;SG;TH;TK;TL;TO;TV;TW;VN;VU;WF;WS
|
||||
Caribbean,CARIB,AG;AI;AW;BB;BL;BS;CU;CW;DM;DO;GD;GP;HT;JM;KN;KY;LC;MF;MQ;MS;PR;SX;TC;TT;VC;VG;VI
|
||||
Central Asia,CAS,KG;KZ;TJ;TM;UZ
|
||||
Commonwealth of Independent States,CIS,AM;AZ;BY;KG;KZ;MD;RU;TJ;UZ
|
||||
Europe,EUR,AD;AL;AM;AT;AZ;BA;BE;BG;BY;CH;CY;CZ;DE;DK;EE;ES;FI;FR;GE;GR;HR;HU;IE;IS;IT;KZ;LI;LT;LU;LV;MC;MD;ME;MK;MT;NL;NO;PL;PT;RO;RS;RU;SE;SI;SK;SM;TR;UA;UK;VA
|
||||
"Europe, the Middle East and Africa",EMEA,AD;AE;AL;AM;AO;AT;AZ;BA;BE;BF;BG;BH;BI;BJ;BW;BY;CD;CF;CG;CH;CI;CM;CV;CY;CZ;DE;DJ;DK;DZ;EE;EG;EH;ER;ES;ET;FI;FR;GA;GE;GH;GM;GN;GQ;GR;GW;HR;HU;IE;IQ;IR;IS;IT;JO;KE;KM;KW;KZ;LB;LI;LR;LS;LT;LU;LV;LY;MA;MC;MD;ME;MG;MK;ML;MR;MT;MU;MW;MZ;NA;NE;NG;NL;NO;OM;PL;PS;PT;QA;RE;RO;RS;RU;RW;SA;SC;SD;SE;SH;SI;SK;SL;SM;SN;SO;SS;ST;SY;SZ;TD;TF;TG;TN;TR;TZ;UA;UG;UK;VA;YE;YT;ZA;ZM;ZW
|
||||
Hispanic America,HISPAM,AR;BO;CL;CO;CR;CU;DO;EC;GT;HN;MX;NI;PA;PE;PR;PY;SV;UY;VE
|
||||
Latin America,LATAM,AR;BL;BO;BR;CL;CO;CR;CU;DO;EC;GF;GP;GT;HN;HT;MF;MQ;MX;NI;PA;PE;PR;PY;SV;UY;VE
|
||||
Latin America and the Caribbean,LAC,AG;AI;AR;AW;BB;BL;BO;BR;BS;CL;CO;CR;CU;CW;DM;DO;EC;GD;GF;GP;GT;HN;HT;JM;KN;KY;LC;MF;MQ;MS;MX;NI;PA;PE;PR;PY;SV;SX;TC;TT;UY;VC;VE;VG;VI
|
||||
Maghreb,MAGHREB,DZ;LY;MA;MR;TN
|
||||
Middle East,MIDEAST,AE;BH;CY;EG;IL;IQ;IR;JO;KW;LB;OM;PS;QA;SA;SY;TR;YE
|
||||
Middle East and North Africa,MENA,AE;BH;CY;DJ;DZ;EG;EH;IL;IQ;IR;JO;KW;LB;LY;MA;OM;PS;QA;SA;SD;SY;TN;TR;YE
|
||||
Nordics,NORD,AX;DK;FO;FI;IS;NO;SE
|
||||
North America,NORAM,AG;AI;AW;BB;BL;BM;BS;BZ;CA;CR;CU;CW;DM;DO;GD;GL;GP;GT;HN;HT;JM;KN;KY;LC;MF;MQ;MS;MX;NI;PA;PM;PR;SV;SX;TC;TT;US;VC;VG;VI
|
||||
Northern America,NAM,BM;CA;GL;PM;US
|
||||
Oceania,OCE,AS;AU;CK;FJ;FM;GU;KI;MH;MP;NC;NF;NR;NU;NZ;PF;PG;PN;PW;SB;TK;TO;TV;VU;WF;WS
|
||||
South Asia,SAS,AF;BD;BT;IN;LK;MV;NP;PK
|
||||
Sub-Saharan Africa,SSA,AO;BF;BI;BJ;BW;CD;CF;CG;CI;CM;CV;DJ;ER;ET;GA;GH;GM;GN;GQ;GW;KE;KM;LR;LS;MG;ML;MR;MU;MW;MZ;NA;NE;NG;RW;SC;SD;SL;SN;SO;SS;ST;SZ;TD;TG;TZ;UG;ZA;ZM;ZW
|
||||
West Africa,WAFR,BF;BJ;CI;CV;GH;GM;GN;GW;LR;ML;MR;NE;NG;SH;SL;SN;TG
|
||||
Worldwide,INT,AD;AE;AF;AG;AI;AL;AM;AO;AQ;AR;AS;AT;AU;AW;AX;AZ;BA;BB;BD;BE;BF;BG;BH;BI;BJ;BL;BM;BN;BO;BQ;BR;BS;BT;BV;BW;BY;BZ;CA;CC;CD;CF;CG;CH;CI;CK;CL;CM;CN;CO;CR;CU;CV;CW;CX;CY;CZ;DE;DJ;DK;DM;DO;DZ;EC;EE;EG;EH;ER;ES;ET;FI;FJ;FK;FM;FO;FR;GA;UK;GD;GE;GF;GG;GH;GI;GL;GM;GN;GP;GQ;GR;GS;GT;GU;GW;GY;HK;HM;HN;HR;HT;HU;ID;IE;IL;IM;IN;IO;IQ;IR;IS;IT;JE;JM;JO;JP;KE;KG;KH;KI;KM;KN;KP;KR;KW;KY;KZ;LA;LB;LC;LI;LK;LR;LS;LT;LU;LV;LY;MA;MC;MD;ME;MF;MG;MH;MK;ML;MM;MN;MO;MP;MQ;MR;MS;MT;MU;MV;MW;MX;MY;MZ;NA;NC;NE;NF;NG;NI;NL;NO;NP;NR;NU;NZ;OM;PA;PE;PF;PG;PH;PK;PL;PM;PN;PR;PS;PT;PW;PY;QA;RE;RO;RS;RU;RW;SA;SB;SC;SD;SE;SG;SH;SI;SJ;SK;SL;SM;SN;SO;SR;SS;ST;SV;SX;SY;SZ;TC;TD;TF;TG;TH;TJ;TK;TL;TM;TN;TO;TR;TT;TV;TW;TZ;UA;UG;UM;US;UY;UZ;VA;VC;VE;VG;VI;VN;VU;WF;WS;XK;YE;YT;ZA;ZM;ZW
|
|
3433
data/subdivisions.csv
Executable file
3433
data/subdivisions.csv
Executable file
File diff suppressed because it is too large
Load diff
1620
package-lock.json
generated
Normal file
1620
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "@iptv-org/database",
|
||||
"scripts": {
|
||||
"act:check": "act pull_request -W .github/workflows/check.yml",
|
||||
"act:deploy": "act push -W .github/workflows/deploy.yml",
|
||||
"db:validate": "node scripts/db/validate.js",
|
||||
"db:export": "node scripts/db/export.js"
|
||||
},
|
||||
"private": true,
|
||||
"author": "Arhey",
|
||||
"dependencies": {
|
||||
"axios": "^0.25.0",
|
||||
"chalk": "^4.1.2",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"commander": "^9.0.0",
|
||||
"csvtojson": "^2.0.10",
|
||||
"glob": "^7.2.0",
|
||||
"joi": "^17.6.0",
|
||||
"json2csv": "^6.0.0-alpha.0",
|
||||
"mz": "^2.7.0",
|
||||
"node-cleanup": "^2.1.2",
|
||||
"signale": "^1.4.0",
|
||||
"slugify": "^1.6.5",
|
||||
"transliteration": "^2.2.0"
|
||||
}
|
||||
}
|
1
scripts/.gitignore
vendored
Normal file
1
scripts/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/bot.js
|
71
scripts/core/csv.js
Normal file
71
scripts/core/csv.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
const csv2json = require('csvtojson')
|
||||
const fs = require('mz/fs')
|
||||
const {
|
||||
Parser,
|
||||
transforms: { flatten },
|
||||
formatters: { stringQuoteOnlyIfNecessary }
|
||||
} = require('json2csv')
|
||||
|
||||
const csv2jsonOptions = {
|
||||
checkColumn: true,
|
||||
trim: true,
|
||||
colParser: {
|
||||
countries: listParser,
|
||||
languages: listParser,
|
||||
categories: listParser,
|
||||
broadcast_area: listParser,
|
||||
is_nsfw: boolParser,
|
||||
logo: nullable,
|
||||
subdivision: nullable,
|
||||
city: nullable,
|
||||
network: nullable
|
||||
}
|
||||
}
|
||||
|
||||
const json2csv = new Parser({
|
||||
transforms: [flattenArray],
|
||||
formatters: {
|
||||
string: stringQuoteOnlyIfNecessary()
|
||||
}
|
||||
})
|
||||
|
||||
const csv = {}
|
||||
|
||||
csv.load = async function (filepath) {
|
||||
return csv2json(csv2jsonOptions).fromFile(filepath)
|
||||
}
|
||||
|
||||
csv.save = async function (filepath, data) {
|
||||
const string = json2csv.parse(data)
|
||||
|
||||
return fs.writeFile(filepath, string)
|
||||
}
|
||||
|
||||
csv.saveSync = function (filepath, data) {
|
||||
const string = json2csv.parse(data)
|
||||
|
||||
return fs.writeFileSync(filepath, string)
|
||||
}
|
||||
|
||||
module.exports = csv
|
||||
|
||||
function flattenArray(item) {
|
||||
for (let prop in item) {
|
||||
const value = item[prop]
|
||||
item[prop] = Array.isArray(value) ? value.join(';') : value
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
function listParser(value) {
|
||||
return value.split(';').filter(i => i)
|
||||
}
|
||||
|
||||
function boolParser(value) {
|
||||
return value === 'true'
|
||||
}
|
||||
|
||||
function nullable(value) {
|
||||
return value === '' ? null : value
|
||||
}
|
68
scripts/core/file.js
Normal file
68
scripts/core/file.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
const path = require('path')
|
||||
const glob = require('glob')
|
||||
const fs = require('mz/fs')
|
||||
|
||||
const file = {}
|
||||
|
||||
file.list = function (pattern) {
|
||||
return new Promise(resolve => {
|
||||
glob(pattern, function (err, files) {
|
||||
resolve(files)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
file.getFilename = function (filepath) {
|
||||
return path.parse(filepath).name
|
||||
}
|
||||
|
||||
file.createDir = async function (dir) {
|
||||
if (await file.exists(dir)) return
|
||||
|
||||
return fs.mkdir(dir, { recursive: true }).catch(console.error)
|
||||
}
|
||||
|
||||
file.exists = function (filepath) {
|
||||
return fs.exists(path.resolve(filepath))
|
||||
}
|
||||
|
||||
file.read = function (filepath) {
|
||||
return fs.readFile(path.resolve(filepath), { encoding: 'utf8' }).catch(console.error)
|
||||
}
|
||||
|
||||
file.append = function (filepath, data) {
|
||||
return fs.appendFile(path.resolve(filepath), data).catch(console.error)
|
||||
}
|
||||
|
||||
file.create = function (filepath, data = '') {
|
||||
filepath = path.resolve(filepath)
|
||||
const dir = path.dirname(filepath)
|
||||
|
||||
return file
|
||||
.createDir(dir)
|
||||
.then(() => file.write(filepath, data))
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
file.write = function (filepath, data = '') {
|
||||
return fs.writeFile(path.resolve(filepath), data, { encoding: 'utf8' }).catch(console.error)
|
||||
}
|
||||
|
||||
file.clear = async function (filepath) {
|
||||
if (await file.exists(filepath)) return file.write(filepath, '')
|
||||
return true
|
||||
}
|
||||
|
||||
file.resolve = function (filepath) {
|
||||
return path.resolve(filepath)
|
||||
}
|
||||
|
||||
file.dirname = function (filepath) {
|
||||
return path.dirname(filepath)
|
||||
}
|
||||
|
||||
file.basename = function (filepath) {
|
||||
return path.basename(filepath)
|
||||
}
|
||||
|
||||
module.exports = file
|
3
scripts/core/index.js
Normal file
3
scripts/core/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
exports.csv = require('./csv')
|
||||
exports.file = require('./file')
|
||||
exports.logger = require('./logger')
|
13
scripts/core/logger.js
Normal file
13
scripts/core/logger.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
const { Signale } = require('signale')
|
||||
|
||||
const options = {}
|
||||
|
||||
const logger = new Signale(options)
|
||||
|
||||
logger.config({
|
||||
displayLabel: false,
|
||||
displayScope: false,
|
||||
displayBadge: false
|
||||
})
|
||||
|
||||
module.exports = logger
|
23
scripts/db/export.js
Normal file
23
scripts/db/export.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
const { csv } = require('../core')
|
||||
const path = require('path')
|
||||
const glob = require('glob')
|
||||
const fs = require('fs')
|
||||
|
||||
const DATA_DIR = process.env.DATA_DIR || './data'
|
||||
const OUTPUT_DIR = process.env.OUTPUT_DIR || './.gh-pages'
|
||||
|
||||
fs.exists(OUTPUT_DIR, function (exists) {
|
||||
if (!exists) {
|
||||
fs.mkdirSync(OUTPUT_DIR)
|
||||
}
|
||||
})
|
||||
|
||||
glob(`${DATA_DIR}/*.csv`, async function (err, files) {
|
||||
for (const inputFile of files) {
|
||||
const inputFilename = path.parse(inputFile).name
|
||||
const outputFile = `${OUTPUT_DIR}/${inputFilename}.json`
|
||||
|
||||
const json = await csv.load(inputFile)
|
||||
fs.writeFileSync(path.resolve(outputFile), JSON.stringify(json))
|
||||
}
|
||||
})
|
10
scripts/db/schemes/categories.js
Normal file
10
scripts/db/schemes/categories.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
const Joi = require('joi')
|
||||
|
||||
module.exports = {
|
||||
id: Joi.string()
|
||||
.regex(/^[a-z]+$/)
|
||||
.required(),
|
||||
name: Joi.string()
|
||||
.regex(/^[A-Z]+$/i)
|
||||
.required()
|
||||
}
|
27
scripts/db/schemes/channels.js
Normal file
27
scripts/db/schemes/channels.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
const Joi = require('joi')
|
||||
|
||||
module.exports = {
|
||||
id: Joi.string()
|
||||
.regex(/^[A-Za-z0-9]+\.[a-z]{2}$/)
|
||||
.required(),
|
||||
name: Joi.string()
|
||||
.regex(/^[\sa-zA-Z\u00C0-\u00FF0-9-!:&.+'/»#%°$@?()]+$/)
|
||||
.required(),
|
||||
network: Joi.string().allow(null),
|
||||
country: Joi.string()
|
||||
.regex(/^[A-Z]{2}$/)
|
||||
.required(),
|
||||
subdivision: Joi.string()
|
||||
.regex(/^[A-Z]{2}-[A-Z0-9]{1,3}$/)
|
||||
.allow(null),
|
||||
city: Joi.string().allow(null),
|
||||
broadcast_area: Joi.array().items(
|
||||
Joi.string().regex(/^(s\/[A-Z]{2}-[A-Z0-9]{1,3}|c\/[A-Z]{2}|r\/[A-Z0-9]{3,7})$/)
|
||||
),
|
||||
languages: Joi.array()
|
||||
.items(Joi.string().regex(/^[a-z]{3}$/))
|
||||
.allow(''),
|
||||
categories: Joi.array().items(Joi.string().regex(/^[a-z]+$/)),
|
||||
is_nsfw: Joi.boolean().required(),
|
||||
logo: Joi.string().uri().allow(null)
|
||||
}
|
16
scripts/db/schemes/countries.js
Normal file
16
scripts/db/schemes/countries.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const Joi = require('joi')
|
||||
|
||||
module.exports = {
|
||||
name: Joi.string()
|
||||
.regex(/^[\sA-Z\u00C0-\u00FF().-]+$/i)
|
||||
.required(),
|
||||
code: Joi.string()
|
||||
.regex(/^[A-Z]{2}$/)
|
||||
.required(),
|
||||
lang: Joi.string()
|
||||
.regex(/^[a-z]{3}$/)
|
||||
.required(),
|
||||
flag: Joi.string()
|
||||
.regex(/^[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]$/)
|
||||
.required()
|
||||
}
|
6
scripts/db/schemes/index.js
Normal file
6
scripts/db/schemes/index.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
exports.channels = require('./channels')
|
||||
exports.categories = require('./categories')
|
||||
exports.countries = require('./countries')
|
||||
exports.languages = require('./languages')
|
||||
exports.regions = require('./regions')
|
||||
exports.subdivisions = require('./subdivisions')
|
8
scripts/db/schemes/languages.js
Normal file
8
scripts/db/schemes/languages.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
const Joi = require('joi')
|
||||
|
||||
module.exports = {
|
||||
code: Joi.string()
|
||||
.regex(/^[a-z]{3}$/)
|
||||
.required(),
|
||||
name: Joi.string().required()
|
||||
}
|
15
scripts/db/schemes/regions.js
Normal file
15
scripts/db/schemes/regions.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const Joi = require('joi')
|
||||
|
||||
module.exports = {
|
||||
name: Joi.string()
|
||||
.regex(/^[\sA-Z\u00C0-\u00FF().,-]+$/i)
|
||||
.required(),
|
||||
code: Joi.string()
|
||||
.regex(/^[A-Z]{3,7}$/)
|
||||
.required(),
|
||||
countries: Joi.array().items(
|
||||
Joi.string()
|
||||
.regex(/^[A-Z]{2}$/)
|
||||
.allow('')
|
||||
)
|
||||
}
|
11
scripts/db/schemes/subdivisions.js
Normal file
11
scripts/db/schemes/subdivisions.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const Joi = require('joi')
|
||||
|
||||
module.exports = {
|
||||
country: Joi.string()
|
||||
.regex(/^[A-Z]{2}$/)
|
||||
.required(),
|
||||
name: Joi.string().required(),
|
||||
code: Joi.string()
|
||||
.regex(/^[A-Z]{2}-[A-Z0-9]{1,3}$/)
|
||||
.required()
|
||||
}
|
84
scripts/db/validate.js
Normal file
84
scripts/db/validate.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
const { logger, file, csv } = require('../core')
|
||||
const { program } = require('commander')
|
||||
const schemes = require('./schemes')
|
||||
const chalk = require('chalk')
|
||||
const Joi = require('joi')
|
||||
|
||||
program.argument('[filepath]', 'Path to file to validate').parse(process.argv)
|
||||
|
||||
async function main() {
|
||||
let errors = []
|
||||
const files = program.args.length
|
||||
? program.args
|
||||
: [
|
||||
'data/categories.csv',
|
||||
'data/channels.csv',
|
||||
'data/countries.csv',
|
||||
'data/languages.csv',
|
||||
'data/regions.csv',
|
||||
'data/subdivisions.csv'
|
||||
]
|
||||
for (const filepath of files) {
|
||||
if (!filepath.endsWith('.csv')) continue
|
||||
const data = await csv.load(filepath)
|
||||
|
||||
const filename = file.getFilename(filepath)
|
||||
|
||||
if (!schemes[filename]) {
|
||||
logger.error(chalk.red(`\nERR: "${filename}" scheme is missing`))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
let fileErrors = []
|
||||
if (filename === 'channels') {
|
||||
fileErrors = fileErrors.concat(findDuplicatesById(data))
|
||||
}
|
||||
|
||||
const schema = Joi.object(schemes[filename])
|
||||
data.forEach((row, i) => {
|
||||
const { error } = schema.validate(row, { abortEarly: false })
|
||||
if (error) {
|
||||
error.details.forEach(detail => {
|
||||
fileErrors.push({ line: i + 2, message: detail.message })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (fileErrors.length) {
|
||||
logger.info(`\n${chalk.underline(filepath)}`)
|
||||
fileErrors.forEach(err => {
|
||||
const position = err.line.toString().padEnd(6, ' ')
|
||||
logger.error(` ${chalk.gray(position)} ${err.message}`)
|
||||
})
|
||||
errors = errors.concat(fileErrors)
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
logger.error(chalk.red(`\n${errors.length} error(s)`))
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
function findDuplicatesById(data) {
|
||||
data = data.map(i => {
|
||||
i.id = i.id.toLowerCase()
|
||||
return i
|
||||
})
|
||||
|
||||
const errors = []
|
||||
const schema = Joi.array().unique((a, b) => a.id === b.id)
|
||||
const { error } = schema.validate(data, { abortEarly: false })
|
||||
if (error) {
|
||||
error.details.forEach(detail => {
|
||||
errors.push({
|
||||
line: detail.context.pos + 2,
|
||||
message: `Entry with the id "${detail.context.value.id}" already exists`
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
Loading…
Reference in a new issue