make first working M3ULoader, however there is huge bug related to M3U parsing that needs to be fixed asap, as well as unit tests are incomplete

This commit is contained in:
mykola2312 2024-04-21 22:50:38 +03:00
parent 4dd212dff8
commit 9cc7f254e4
7 changed files with 124 additions and 29 deletions

2
.gitignore vendored
View file

@ -43,3 +43,5 @@ build/
config.json
*.db
log/
*.m3u
*.m3u8

View file

@ -18,12 +18,12 @@
"type": "m3u",
"url": "https://example.com/list.m3u",
"cookies": null,
"singleCategory": null
"rootCategory": null
},
{
"type": "m3u-local",
"path": "test.m3u8",
"singleCategory": "test"
"rootCategory": "test"
}
]
}

View file

@ -1,18 +1,28 @@
package com.mykola2312.mptv;
import com.mykola2312.mptv.config.Config;
import com.mykola2312.mptv.config.SourceItem;
import com.mykola2312.mptv.db.DB;
import com.mykola2312.mptv.db.M3ULoader;
import com.mykola2312.mptv.parser.M3U;
import com.mykola2312.mptv.parser.M3UException;
import com.mykola2312.mptv.parser.M3UParser;
import com.mykola2312.mptv.ui.MainFrame;
import org.apache.commons.cli.*;
import org.apache.log4j.Logger;
import org.flywaydb.core.Flyway;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
public class Main {
private static final Logger logger = Logger.getLogger(Main.class);
public static void main(String[] args) {
// parse command line
final Options options = new Options();
options.addOption(Option
.builder("c")
@ -29,6 +39,7 @@ public class Main {
return;
}
// load config
final String configPath = cmd.hasOption('c') ? cmd.getOptionValue('c') : "config.json";
Config config;
try {
@ -45,6 +56,7 @@ public class Main {
return;
}
// setup db
try {
DB.setupFromConfig(config.db);
} catch (RuntimeException e) {
@ -54,14 +66,49 @@ public class Main {
return;
}
// migrate db
Flyway flyway = new Flyway(
Flyway.configure()
.dataSource(DB.URL, DB.USER, DB.PASSWORD)
.baselineOnMigrate(true)
.load()
.getConfiguration()
);
flyway.migrate();
// load sources, start crawlers
for (SourceItem source : config.sources) {
switch (source.type) {
case M3U_LOCAL -> {
try {
if (source.path == null) {
logger.error("m3u local has to have \"path\" variable");
continue;
} else if (source.rootCategory == null) {
logger.error("source has to have \"rootCategory\"");
continue;
}
String m3uData = Files.readString(Paths.get(source.path), StandardCharsets.UTF_8);
ArrayList<M3U> m3u = M3UParser.parse(m3uData);
M3ULoader.loadAll(m3u, source.rootCategory);
} catch (IOException e) {
logger.error(e);
logger.error(String.format("failed to read local m3u file: %s", e.getMessage()));
} catch (M3UException e) {
logger.error(e);
logger.error(String.format("failed to parse m3u: %s", e.getMessage()));
}
}
default -> {
logger.error(String.format("source type %s is not implemented yet :(", source.type.name()));
}
}
}
// initialize ui
MainFrame frame = new MainFrame();
frame.create(config.frame);

View file

@ -26,5 +26,5 @@ public class SourceItem {
public String cookies;
@Nullable
public String singleCategory;
public String rootCategory;
}

View file

@ -3,43 +3,89 @@ package com.mykola2312.mptv.db;
import java.util.ArrayList;
import java.util.HashMap;
import org.jooq.*;
import org.jooq.exception.NoDataFoundException;
import org.jooq.impl.*;
import static com.mykola2312.mptv.tables.Category.*;
import static com.mykola2312.mptv.tables.Channel.*;
import com.mykola2312.mptv.db.pojo.Category;
import com.mykola2312.mptv.parser.M3U;
public class M3ULoader {
public static void loadAll(ArrayList<M3U> items) {
private static Integer ensureRootCategory(String rootName) {
try {
return DSL.using(DB.CONFIG)
.select(CATEGORY.ID)
.from(CATEGORY)
.where(CATEGORY.TITLE.eq(rootName))
.limit(1)
.fetchSingleInto(Integer.class);
} catch (NoDataFoundException e) {
return DSL.using(DB.CONFIG)
.insertInto(CATEGORY, CATEGORY.TITLE)
.values(rootName)
.returningResult(CATEGORY.ID)
.fetchSingleInto(Integer.class);
}
}
public static void loadAll(ArrayList<M3U> items, String rootName) {
Integer rootCategoryId = ensureRootCategory(rootName);
// cache categories' ids
HashMap<String, Integer> categories = new HashMap<>();
for (M3U item : items) {
// category
Integer categoryId;
if (item.groupTitle != null) {
Integer id;
Category category = DSL.using(DB.CONFIG)
.select()
.from(CATEGORY)
.where(CATEGORY.TITLE.eq(item.groupTitle))
.limit(1)
.fetchOne()
.into(Category.class);
if (category == null) {
id = DSL.using(DB.CONFIG)
.insertInto(CATEGORY, CATEGORY.TITLE)
.values(item.groupTitle)
.returningResult(CATEGORY.ID)
.fetchOne()
.into(Integer.class);
} else {
id = category.id;
}
categoryId = categories.get(item.groupTitle);
if (categoryId == null) {
Integer id;
try {
id = DSL.using(DB.CONFIG)
.select(CATEGORY.ID)
.from(CATEGORY)
.where(CATEGORY.TITLE.eq(item.groupTitle))
.limit(1)
.fetchSingleInto(Integer.class);
} catch (NoDataFoundException e) {
id = DSL.using(DB.CONFIG)
.insertInto(CATEGORY, CATEGORY.TITLE)
.values(item.groupTitle)
.returningResult(CATEGORY.ID)
.fetchOne()
.into(Integer.class);
}
categories.put(item.groupTitle, id);
categories.put(item.groupTitle, id);
categoryId = id;
}
} else {
categoryId = rootCategoryId;
}
// channel
try {
Integer channelId = DSL.using(DB.CONFIG)
.select(CHANNEL.ID)
.from(CHANNEL)
.where(CHANNEL.CATEGORY.eq(categoryId)
.and(CHANNEL.TITLE.eq(item.title)))
.limit(1)
.fetchSingleInto(Integer.class);
DSL.using(DB.CONFIG)
.update(CHANNEL)
.set(CHANNEL.URL, item.url)
.set(CHANNEL.LOGO, item.tvgLogo)
.where(CHANNEL.ID.eq(channelId))
.execute();
} catch (NoDataFoundException e) {
DSL.using(DB.CONFIG)
.insertInto(CHANNEL,
CHANNEL.CATEGORY, CHANNEL.TITLE,
CHANNEL.URL, CHANNEL.LOGO)
.values(categoryId, item.title, item.url, item.tvgLogo)
.execute();
}
}
}
}

View file

@ -15,4 +15,4 @@ CREATE TABLE channel (
FOREIGN KEY (category) REFERENCES category(id)
);
CREATE INDEX idx_channel_title ON channel(title);
CREATE INDEX idx_channel_category_title ON channel(category,title);

View file

@ -83,12 +83,12 @@ public class TestConfig {
assertEquals("https://example.com/list.m3u", m3u.url);
assertNull(m3u.path);
assertNull(m3u.cookies);
assertNull(m3u.singleCategory);
assertNull(m3u.rootCategory);
SourceItem m3uLocal = config.sources.get(1);
assertEquals(SourceItem.SourceType.M3U_LOCAL, m3uLocal.type);
assertEquals("test.m3u8", m3uLocal.path);
assertEquals("test", m3uLocal.singleCategory);
assertEquals("test", m3uLocal.rootCategory);
assertNull(m3uLocal.url);
assertNull(m3uLocal.cookies);
}