jose 73 Posted February 25, 2017 Posted February 25, 2017 (edited) Just thought i shared this if anyone wanted to use it: I was looking into automating hiding commercials from my recordings my requirements: Has to work in linux (In my case fedora) Emby should trigger it after the recording is done (command line) Mark commercials as chapters and not remove them, I dont need a copy of the file if the commercial are identified incorrectly I found the following free software to accomplish this: comskip (easy to build in linux and also available already compiled for windows and other OS) mkvtoolnix (widely available for a multitude of distributions precompiled) python (easy to program with but can be changed to you programming of choice) How it works: emby starts a python script after a recording is finished,. (the recording has to saved as mkv) python script: run the video through comskip and produes an edl file with the location of the commercials create a list of chapters based on the edl file create one chapter list with only the chapters that dont have commercials and a list with all chapters run the video through mkvpropedit , edits the header or the file (fast operation) and adds two editions on the file one without commercial and one with commercials. For now if you watch the video through emby only the chapters are recognized but it wont skip commercials as ffmpeg doesnt support ordered chapters. If you watch the video through vlc or kodi it selects by default the no commercial track and plays fine. #!/usr/bin/env python3 import os import xmltodict import datetime import subprocess import sys class EDLEntry: def __init__(self, entryLine): print(entryLine) a = entryLine.strip().split(None,3); print(a) self.Start = float(a[0]) self.End = float(a[1]) self.Type = float(a[2]) def __lt__(self, other): if hasattr(other, 'Start'): return self.Start < other.Start class EDL: def __init__(self, filepath): self.Entries = [] self.Entries.extend([EDLEntry(line) for line in open(filepath)]) def GetChapters(self): chapters = [] firstIsCommercial = False sorted(self.Entries) i = 0 l = len(self.Entries) if l==0: return chapters if self.Entries[0].Start != 0.0: chapters.append(Chapter(0,"Show",self.Entries[0].Start)) for comercial in self.Entries: i += 1 show = Chapter(comercial.End,"Show") if i < l: show.End = self.Entries[i].Start chapters.extend([ Chapter(comercial.Start,"Comercial",comercial.End), show ]) else: chapters.extend([Chapter(comercial.Start,"Comercial",comercial.End)]) return chapters def getTimespanFromSeconds(s = 0): return "{:0>8}".format(str(datetime.timedelta(seconds=s))) class Chapter: def __init__(self, start=0.0, title = "Chapter", end = None, lang = None): self.Start = start self.Title = title self.End = end self.Lang = lang def GenerateChapterAtom(self, i = None): xml = { 'ChapterFlagEnabled':1, 'ChapterTimeStart':getTimespanFromSeconds(self.Start), 'ChapterDisplay':{ 'ChapterString': self.Title } } if self.Lang != None: xml["ChapterDisplay"]["ChapterLanguage"] = lang if self.End != None: xml["ChapterTimeEnd"] = getTimespanFromSeconds(self.End), return xml def __lt__(self, other): if hasattr(other, 'Start'): return self.Start < other.Start class EditionEntry: def __init__(self, chapters = None, uid = None): self.Chapters = chapters if chapters != None else [] self.UID = uid def GetEditionEntry(self): return {'ChapterAtom':[chapter.GenerateChapterAtom() for chapter in sorted(self.Chapters)],'EditionFlagOrdered':1,'EditionUID':self.UID} class Video: def __init__(self): self.Editions = [] self.Tags = {"Tags":{'Tag':[]}} def AddEdition(self, chapters, title): uid = len(self.Editions)+1 self.Editions.append(EditionEntry(chapters,uid)) self.Tags["Tags"]['Tag'].append({ "Targets":{ "EditionUID":uid, "TargetTypeValue":50 }, "Simple":{ "Name":"TITLE", "String":title, "TagLanguage":"eng", "DefaultLanguage":1 } }) def Export(self, filepath): dict = {"Chapters":{"EditionEntry":[edition.GetEditionEntry() for edition in self.Editions]}} result = xmltodict.unparse(dict, encoding="ISO-8859-1", pretty=True) with open(filepath+".chapters", "w") as text_file: print(result, file=text_file) result = xmltodict.unparse(self.Tags, encoding="ISO-8859-1", pretty=True) with open(filepath+".tags", "w") as text_file: print(result, file=text_file) if __name__== "__main__": name = sys.argv[1] inipath = os.path.splitext(sys.argv[2])[0]+".ini" path = os.path.splitext(name)[0] try: with subprocess.Popen("/usr/local/bin/comskip --ini='\"{1}\"' '{0}.mkv'".format(path,inipath), shell=True,stdout=subprocess.PIPE,) as p: for line in p.stdout: print(line.decode(), end='') chapters = EDL(path+".edl").GetChapters() v = Video() v.AddEdition([chapter for chapter in chapters if chapter.Title == "Show"],'Without Commercials') v.AddEdition(chapters,'With Comercials') v.Export(path) with subprocess.Popen("/bin/mkvpropedit --chapters '' '{0}.mkv'".format(path), shell=True,stdout=subprocess.PIPE) as p: for line in p.stdout: print(line.decode(), end='') with subprocess.Popen("/bin/mkvpropedit -t all:'{0}.tags' --chapters '{0}.chapters' '{0}.mkv'".format(path), shell=True,stdout=subprocess.PIPE) as p: for line in p.stdout: print(line.decode(),end='') except: print("Unexpected error:", sys.exc_info()[0]) Edited February 25, 2017 by jose 2
Tur0k 148 Posted September 14, 2017 Posted September 14, 2017 This looks really close to what I am trying to do. Would you be willing to assist me in adapting this to my use case? I would like to: 1. use comskip to identify commercial segments 2. use mkvmerge to split the video. 3. merge the video without the commercials. I run Emby on Windows 10, and have installed Comskip, Python and mkvtoolnix on my system. I assume that I need to take your script and put it into a .py script. 1
naeonline 27 Posted September 15, 2017 Posted September 15, 2017 @@Tur0k Can you PM me a copy of a .edl or .xml file you have created with comskip. I'm pretty sure i can get this to work with ffmpeg. 2
Uuugh 4 Posted March 2, 2018 Posted March 2, 2018 @@Tur0k Can you PM me a copy of a .edl or .xml file you have created with comskip. I'm pretty sure i can get this to work with ffmpeg. Any luck merging a commercial free mkv? I use MCEBuddy with comskip in Windows t trim my commericals. It's the only thing holding me back from switching my media server to Linux. Thanks
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now