Skip to content
Open
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
15 changes: 15 additions & 0 deletions scripts/commands/db/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,21 @@ async function removeFeed(issue: Issue) {
return
}

if (foundFeed.is_main) {
const nextFeed = data.feeds.first(
(feed: Feed) => feed.channel === channelId && feed.id !== feedId
)
if (!nextFeed) {
log.error(
`The feed with ID "${feedId}" is the only feed for the "${channelId}" channel and therefore cannot be deleted`
)
skippedIssues.add(issue)
return
}
nextFeed.is_main = true
onFeedNewMain(channelId, nextFeed.id, log)
}

data.feeds.remove((feed: Feed) => feed.getStreamId() === foundFeed.getStreamId())
data.feedsKeyByStreamId.remove(foundFeed.getStreamId())

Expand Down
21 changes: 21 additions & 0 deletions scripts/commands/issue/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,24 @@ function validateAddCityRequest(dataSet: DataSet) {
if (!cityCode) {
errors.push('The request is missing the "City Code"')
done()
} else {
const isDuplicate = data.citiesKeyByCode.has(cityCode)
if (isDuplicate) {
errors.push(`The database already contains a city with code "${cityCode}"`)
done()
}
}

const wikidataId = dataSet.getString('wikidata_id')?.trim()
if (!wikidataId) {
errors.push('The request is missing the "Wikidata ID"')
done()
} else {
const isDuplicate = data.citiesKeyByWikidataId.has(wikidataId)
if (isDuplicate) {
errors.push(`The database already contains a city with wikidata_id "${wikidataId}"`)
done()
}
}

validateCityData(dataSet)
Expand Down Expand Up @@ -326,6 +338,15 @@ function validateAddLogoRequest(dataSet: DataSet) {
if (!logoUrl) {
errors.push('The request is missing the "Logo URL"')
done()
} else {
const foundLogos = data.logosGroupedByUrl.get(logoUrl) || []
const duplicate = foundLogos.find(logo => logo.channel === channelId)
if (duplicate) {
errors.push(
`The database already contains a logo with url "${logoUrl}" and the channel "${channelId}"`
)
done()
}
}

validateLogoData(dataSet)
Expand Down
16 changes: 8 additions & 8 deletions scripts/core/dataSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,37 +80,37 @@ export class DataSet {
}

getBoolean(key: string): boolean | undefined {
if (this.isDeleted(key)) return undefined

if (this.missing(key)) return undefined

return this.#data.get(key) === 'TRUE' ? true : false
}

getString(key: string): string | undefined {
const deleteSymbol = '~'
if (this.isDeleted(key)) return undefined

return this.missing(key)
? undefined
: this.#data.get(key) === deleteSymbol
? ''
: String(this.#data.get(key))
return this.missing(key) ? undefined : String(this.#data.get(key))
}

getNumber(key: string): number | undefined {
if (this.isDeleted(key)) return undefined

const string = this.getString(key)

return string ? Number(string) : undefined
}

getArray(key: string): string[] | undefined {
const deleteSymbol = '~'
if (this.isDeleted(key)) return undefined

if (this.#data.missing(key)) return undefined

const value = this.#data.get(key)

if (typeof value !== 'string') return undefined

return value === deleteSymbol ? [] : value.split(/[\r\n;]/)
return value.split(/[\r\n;]/)
}

getChanged(): string[] {
Expand Down
5 changes: 5 additions & 0 deletions scripts/core/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ let data: DatabaseData = {
logos: new Collection<Logo>(),

citiesKeyByCode: new Dictionary<City>(),
citiesKeyByWikidataId: new Dictionary<City>(),
feedsGroupedByChannelId: new Dictionary<Feed[]>(),
feedsKeyByStreamId: new Dictionary<Feed>(),
channelsKeyById: new Dictionary<Channel>(),
Expand Down Expand Up @@ -62,6 +63,7 @@ let cache: DatabaseData = {
logos: new Collection<Logo>(),

citiesKeyByCode: new Dictionary<City>(),
citiesKeyByWikidataId: new Dictionary<City>(),
feedsGroupedByChannelId: new Dictionary<Feed[]>(),
feedsKeyByStreamId: new Dictionary<Feed>(),
channelsKeyById: new Dictionary<Channel>(),
Expand Down Expand Up @@ -174,6 +176,7 @@ async function loadData(): Promise<DatabaseData> {
(subdivision: Subdivision) => subdivision.code
)
data.citiesKeyByCode = data.cities.keyBy((city: City) => city.code)
data.citiesKeyByWikidataId = data.cities.keyBy((city: City) => city.wikidata_id)

const locations: Collection<Location> = new Collection()
data.cities.forEach(city => {
Expand Down Expand Up @@ -212,6 +215,7 @@ function cacheData() {
countries: data.countries.clone(),
logos: data.logos.clone(),
citiesKeyByCode: data.citiesKeyByCode.clone(),
citiesKeyByWikidataId: data.citiesKeyByWikidataId.clone(),
feedsGroupedByChannelId: data.feedsGroupedByChannelId.clone(),
feedsKeyByStreamId: data.feedsKeyByStreamId.clone(),
channelsKeyById: data.channelsKeyById.clone(),
Expand Down Expand Up @@ -241,6 +245,7 @@ function resetData() {
countries: cache.countries,
logos: cache.logos,
citiesKeyByCode: cache.citiesKeyByCode,
citiesKeyByWikidataId: cache.citiesKeyByWikidataId,
feedsGroupedByChannelId: cache.feedsGroupedByChannelId,
feedsKeyByStreamId: cache.feedsKeyByStreamId,
channelsKeyById: cache.channelsKeyById,
Expand Down
16 changes: 8 additions & 8 deletions scripts/models/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ export class Channel extends sdk.Models.Channel implements Validator {
update(dataSet: DataSet): this {
const data = {
channel_name: dataSet.getString('channel_name'),
alt_names: dataSet.getArray('alt_names'),
network: dataSet.getString('network'),
owners: dataSet.getArray('owners'),
alt_names: dataSet.isDeleted('alt_names') ? [] : dataSet.getArray('alt_names'),
network: dataSet.isDeleted('network') ? null : dataSet.getString('network'),
owners: dataSet.isDeleted('owners') ? [] : dataSet.getArray('owners'),
country: dataSet.getString('country'),
categories: dataSet.getArray('categories'),
categories: dataSet.isDeleted('categories') ? [] : dataSet.getArray('categories'),
is_nsfw: dataSet.getBoolean('is_nsfw'),
launched: dataSet.getString('launched'),
closed: dataSet.getString('closed'),
replaced_by: dataSet.getString('replaced_by'),
website: dataSet.getString('website')
launched: dataSet.isDeleted('launched') ? null : dataSet.getString('launched'),
closed: dataSet.isDeleted('closed') ? null : dataSet.getString('closed'),
replaced_by: dataSet.isDeleted('replaced_by') ? null : dataSet.getString('replaced_by'),
website: dataSet.isDeleted('website') ? null : dataSet.getString('website')
}

if (data.channel_name !== undefined) this.name = data.channel_name
Expand Down
2 changes: 1 addition & 1 deletion scripts/models/feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class Feed extends sdk.Models.Feed implements Validator {
update(dataSet: DataSet): this {
const data = {
feed_name: dataSet.getString('feed_name'),
alt_names: dataSet.getArray('alt_names'),
alt_names: dataSet.isDeleted('alt_names') ? [] : dataSet.getArray('alt_names'),
is_main: dataSet.getBoolean('is_main'),
broadcast_area: dataSet.getArray('broadcast_area'),
timezones: dataSet.getArray('timezones'),
Expand Down
4 changes: 2 additions & 2 deletions scripts/models/logo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ export class Logo extends sdk.Models.Logo implements Validator {
update(dataSet: DataSet): this {
const data = {
channel: dataSet.getString('new_channel_id'),
feed: dataSet.getString('new_feed_id'),
feed: dataSet.isDeleted('new_feed_id') ? null : dataSet.getString('new_feed_id'),
in_use: dataSet.getBoolean('in_use'),
tags: dataSet.getArray('tags'),
tags: dataSet.isDeleted('tags') ? [] : dataSet.getArray('tags'),
width: dataSet.getNumber('width'),
height: dataSet.getNumber('height'),
format: dataSet.getString('format')
Expand Down
1 change: 1 addition & 0 deletions scripts/types/db.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type DatabaseData = {
regions: Collection<Region>
subdivisions: Collection<Subdivision>
cities: Collection<City>
citiesKeyByWikidataId: Dictionary<City>
citiesKeyByCode: Dictionary<City>
channelsKeyById: Dictionary<Channel>
countriesKeyByCode: Dictionary<Country>
Expand Down
1 change: 1 addition & 0 deletions tests/__data__/expected/db/update/data/feeds.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
channel,id,name,alt_names,is_main,broadcast_area,timezones,languages,format
01TV.fr,HD,HD,,TRUE,c/FR,Europe/Paris,fra,576i
0TV.dk,SD,SD,,TRUE,c/DK,Europe/Copenhagen,dan,576i
1000xHoraTV.uy,HD,HD,Oeste;Este,TRUE,c/CN,Africa/Johannesburg;Africa/Kigali,zho,576i
1000xHoraTV.uy,SD,SD,,FALSE,c/UY,America/Montevideo,spa,576i
Expand Down
3 changes: 2 additions & 1 deletion tests/__data__/expected/db/update/data/logos.csv
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ M5.hu,HD,TRUE,,512,512,PNG,https://i.imgur.com/y21wFd0.png
WenzhouEconomicandEducation.cn,,TRUE,,80,80,JPEG,https://www.tvchinese.net/uploads/tv/wzjjkj.jpg
YiwuBusinessChannel.cn,,TRUE,horizontal;color,80,80,JPEG,https://www.tvchinese.net/uploads/tv/yiwutv.jpg
YiwuNewsIntegratedChannel.cn,,FALSE,horizontal,80,80,JPEG,https://www.tvchinese.net/uploads/tv/yiwutv.jpg
ZonaDAZN3.it,HD,TRUE,,400,400,PNG,https://i.imgur.com/Jop3Vip.png
ZonaDAZN3.it,,TRUE,,400,400,PNG,https://i.imgur.com/Jop3Vip.png
ZonaDAZN3.it,,TRUE,,400,400,PNG,https://i.imgur.com/Jop3Vip.png
ZTVWorld.hu,,TRUE,,0,0,PNG,https://i.imgur.com/wPqCtwR.png
ZutTV.ve,HD,TRUE,,0,0,PNG,https://i.imgur.com/wPqCtwK.png
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The request contains error(s):
- The database already contains a city with wikidata_id "Q386802"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The request contains error(s):
- The database already contains a logo with url "https://i.imgur.com/7oNe8xj.png" and the channel "SagarmathaTV.np"
3 changes: 2 additions & 1 deletion tests/__data__/input/db/update/data/feeds.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
channel,id,name,alt_names,is_main,broadcast_area,timezones,languages,format
002RadioTV.do,SD,SD,,TRUE,c/DO,America/Santo_Domingo,spa,480i
01TV.fr,SD,SD,,TRUE,c/FR,Europe/Paris,fra,576i
01TV.fr,HD,HD,,FALSE,c/FR,Europe/Paris,fra,576i
0TV.dk,SD,SD,,TRUE,c/DK,Europe/Copenhagen,dan,576i
1000xHoraTV.uy,SD,SD,,TRUE,c/UY,America/Montevideo,spa,576i
24HorasInternacional.es,SD,SD,,TRUE,c/ES,Europe/Madrid,spa,576i
Expand All @@ -13,7 +14,7 @@ ZonaDAZN3.it,SD,SD,,FALSE,c/IT,Europe/Rome,ita,576i
BeijingSatelliteTV.cn,SD,SD,,TRUE,c/DO,America/Santo_Domingo,spa,480i
M5.hu,SD,SD,Sud,FALSE,c/DO,America/Santo_Domingo,spa,480i
M5.hu,West,West,,TRUE,c/DO,America/Santo_Domingo,spa,480i
Channel82.bm,SD,SD,,FALSE,c/BM,America/Santo_Domingo,eng,480i
Channel82.bm,SD,SD,ch82,FALSE,c/BM,America/Santo_Domingo,eng,480i
TrueCrime.uk,SD,SD,,TRUE,c/UK;c/IE,Europe/London,eng,576i
ZutTV.ve,SD,SD,,TRUE,c/UK;c/IE;ct/ALMIL,Europe/London,eng,576i
ZTVWorld.hu,SD,SD,,TRUE,c/HU,Europe/London,eng,576i
Expand Down
2 changes: 1 addition & 1 deletion tests/__data__/input/db/update/data/logos.csv
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ BeijingSatelliteTV.cn,,TRUE,,512,512,PNG,https://i.imgur.com/vsktAez.png
M5.hu,SD,TRUE,,512,512,PNG,https://i.imgur.com/y21wFd0.png
ZonaDAZN2.it,SD,TRUE,,512,512,PNG,https://i.imgur.com/vMdyLVv.png
ZonaDAZN3.it,SD,TRUE,,512,512,PNG,https://i.imgur.com/Jop3Vip.png
ZonaDAZN3.it,HD,TRUE,,512,512,PNG,https://i.imgur.com/Jop3Vip.png
ZonaDAZN3.it,HD,TRUE,test,512,512,PNG,https://i.imgur.com/Jop3Vip.png
K04GWD1.us,,TRUE,,0,0,PNG,https://upload.wikimedia.org/wikipedia/en/thumb/3/33/PBS_logo.svg/512px-PBS_logo.svg.png
K04JRD1.us,,TRUE,,0,0,PNG,https://upload.wikimedia.org/wikipedia/en/thumb/3/33/PBS_logo.svg/512px-PBS_logo.svg.png
K05FWD1.us,,TRUE,,0,0,PNG,https://upload.wikimedia.org/wikipedia/en/thumb/3/33/PBS_logo.svg/512px-PBS_logo.svg.png
Expand Down
4 changes: 2 additions & 2 deletions tests/__data__/input/db/update/issues.js
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ module.exports = [
type: null,
active_lock_reason: null,
sub_issues_summary: { total: 0, completed: 0, percent_completed: 0 },
body: '### Channel ID (required)\n\nChannel82.bm\n\n### Feed ID (required)\n\nSD\n\n### Feed Name\n\n_No response_\n\n### Main Feed\n\nNone\n\n### Broadcast Area\n\n_No response_\n\n### Timezones\n\nAtlantic/Bermuda\n\n### Languages\n\n_No response_\n\n### Format\n\nNone\n\n### Notes\n\n_No response_',
body: '### Channel ID (required)\n\nChannel82.bm\n\n### Feed ID (required)\n\nSD\n\n### Alternative Names\n\n~\n\n### Feed Name\n\n_No response_\n\n### Main Feed\n\nNone\n\n### Broadcast Area\n\n_No response_\n\n### Timezones\n\nAtlantic/Bermuda\n\n### Languages\n\n_No response_\n\n### Format\n\nNone\n\n### Notes\n\n_No response_',
closed_by: null,
reactions: {
url: 'https://api.github.com/repos/iptv-org/database/issues/17612/reactions',
Expand Down Expand Up @@ -1408,7 +1408,7 @@ module.exports = [
closed_at: null,
author_association: 'CONTRIBUTOR',
active_lock_reason: null,
body: '### Logo URL (required)\n\nhttps://i.imgur.com/Jop3Vip.png\n\n### Tags\n\n_No response_\n\n### Width\n\n400\n\n### Height\n\n400\n\n### Format\n\nPNG\n\n### Notes\n\n_No response_',
body: '### Logo URL (required)\n\nhttps://i.imgur.com/Jop3Vip.png\n\n### New Feed ID\n\n~\n\n### Tags\n\n~\n\n### Width\n\n400\n\n### Height\n\n400\n\n### Format\n\nPNG\n\n### Notes\n\n_No response_',
reactions: {
url: 'https://api.github.com/repos/iptv-org/database/issues/9903/reactions',
total_count: 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
channel,feed,in_use,tags,width,height,format,url
OmkarTV.np,HD,TRUE,,334,210,PNG,https://i.imgur.com/7oNe8xj.png
SagarmathaTV.np,SD,TRUE,,334,210,PNG,https://i.imgur.com/7oNe8xj.png
SagarmathaTV.np,HD,TRUE,,334,210,PNG,https://i.imgur.com/7oNe8xj.png
Original file line number Diff line number Diff line change
Expand Up @@ -1524,7 +1524,7 @@ module.exports = [
blocking: 0,
total_blocking: 0
},
body: '### Channel ID\n\nOmkarTV.np\n\n### Feed ID (optional)\n\nHD\n\n### Logo URL\n\nhttps://i.imgur.com/HR4FCLt.png\n\n### In Use\n\nTRUE\n\n### Tags (optional)\n\n_No response_\n\n### Notes (optional)\n\n_No response_',
body: '### Channel ID\n\nSagarmathaTV.np\n\n### Feed ID (optional)\n\nHD\n\n### Logo URL\n\n https://i.imgur.com/7oNe8xj.png\n\n### In Use\n\nTRUE\n\n### Tags (optional)\n\n_No response_\n\n### Notes (optional)\n\n_No response_',
closed_by: null,
reactions: {
url: 'https://api.github.com/repos/iptv-org/database/issues/31772/reactions',
Expand Down Expand Up @@ -3444,5 +3444,96 @@ module.exports = [
performed_via_github_app: null,
state_reason: null,
pinned_comment: null
},
{
url: 'https://api.github.com/repos/iptv-org/database/issues/31989',
repository_url: 'https://api.github.com/repos/iptv-org/database',
labels_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/labels{/name}',
comments_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/comments',
events_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/events',
html_url: 'https://github.com/iptv-org/database/issues/31989',
id: 5169121848,
node_id: 'I_kwDOG1Kwp88AAAABNBqKOA',
number: 31989,
title: 'Add: Boston',
user: {
login: 'cancerbikash-oss',
id: 268401535,
node_id: 'U_kgDOD_97fw',
avatar_url: 'https://avatars.githubusercontent.com/u/268401535?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/cancerbikash-oss',
html_url: 'https://github.com/cancerbikash-oss',
followers_url: 'https://api.github.com/users/cancerbikash-oss/followers',
following_url: 'https://api.github.com/users/cancerbikash-oss/following{/other_user}',
gists_url: 'https://api.github.com/users/cancerbikash-oss/gists{/gist_id}',
starred_url: 'https://api.github.com/users/cancerbikash-oss/starred{/owner}{/repo}',
subscriptions_url: 'https://api.github.com/users/cancerbikash-oss/subscriptions',
organizations_url: 'https://api.github.com/users/cancerbikash-oss/orgs',
repos_url: 'https://api.github.com/users/cancerbikash-oss/repos',
events_url: 'https://api.github.com/users/cancerbikash-oss/events{/privacy}',
received_events_url: 'https://api.github.com/users/cancerbikash-oss/received_events',
type: 'User',
user_view_type: 'public',
site_admin: false
},
labels: [
{
id: 5366738347,
node_id: 'LA_kwDOG1Kwp88AAAABP-Htqw',
url: 'https://api.github.com/repos/iptv-org/database/labels/approved',
name: 'approved',
color: '85DDDE',
default: false,
description: ''
},
{
id: 8870945667,
node_id: 'LA_kwDOG1Kwp88AAAACEL_jgw',
url: 'https://api.github.com/repos/iptv-org/database/labels/cities:add',
name: 'cities:add',
color: '497676',
default: false,
description: 'Request to add the city'
}
],
state: 'open',
locked: false,
assignees: [],
milestone: null,
comments: 0,
created_at: '2026-08-17T06:52:12Z',
updated_at: '2026-08-17T06:52:12Z',
closed_at: null,
assignee: null,
author_association: 'NONE',
issue_field_values: [],
type: null,
active_lock_reason: null,
sub_issues_summary: { total: 0, completed: 0, percent_completed: 0 },
issue_dependencies_summary: {
blocked_by: 0,
total_blocked_by: 0,
blocking: 0,
total_blocking: 0
},
body: '### Country\n\nUS\n\n### Subdivision (optional)\n\nOH\n\n### City Name\n\nHuston\n\n### City Code\n\nUSHUS\n\n### Wikidata ID\n\nQ386802\n\n### Notes (optional)\n\n_No response_',
closed_by: null,
reactions: {
url: 'https://api.github.com/repos/iptv-org/database/issues/31989/reactions',
total_count: 0,
'+1': 0,
'-1': 0,
laugh: 0,
hooray: 0,
confused: 0,
heart: 0,
rocket: 0,
eyes: 0
},
timeline_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/timeline',
performed_via_github_app: null,
state_reason: null,
pinned_comment: null
}
]
Loading
Loading