def dup(self): current_scene = S.obs_scene_from_source( S.obs_frontend_get_current_scene()) scene_item = S.obs_scene_find_source(current_scene, self.source_name) info = S.obs_transform_info() crop = S.obs_sceneitem_crop() S.obs_sceneitem_get_info(scene_item, info) S.obs_sceneitem_get_crop(scene_item, crop) duplicate = S.obs_sceneitem_get_source(scene_item) duplicated = S.obs_source_duplicate(duplicate, "duplicate" + self.source_name, False) scenes = S.obs_frontend_get_scenes() for scene in scenes: name = S.obs_source_get_name(scene) if name == self.scene_name: scene = S.obs_scene_from_source(scene) scene_item2 = S.obs_scene_add(scene, duplicated) S.obs_sceneitem_set_info(scene_item2, info) S.obs_sceneitem_set_crop(scene_item2, crop) S.obs_scene_release(scene) S.obs_source_release(duplicated) S.source_list_release(scenes) S.obs_scene_release(current_scene)
def get_order(scene_items=None): order = list() for i, s in enumerate(scene_items): source = obs.obs_sceneitem_get_source(s) name = obs.obs_source_get_name(source) order.append({"index": i, "name": name, "scene_item": s}) return order
def iterSceneItemsByName(self, sourceName): """ Iterator over scene items with a given source name, in the scene currently displayed in the frontend """ # This took me a while to figure out, so I'll comment it # enough to be understandable. # First, we get the source we need to find items of with getSourceByName(sourceName) as s: if s is None: return [] # Now we get the entire scene that's currently streaming with frontendGetCurrentScene() as currentSceneSource: if currentSceneSource is None: return [] # (and convert it to a scene) currentScene = obs.obs_scene_from_source(currentSceneSource) if currentScene is None: return [] # Now we iterate over all the items in that scene with sceneEnumItems(currentScene) as items: for item in items: if item is None: continue # Now we find what source this item is using itemSource = obs.obs_sceneitem_get_source(item) # And the name of that source itemSourceName = obs.obs_source_get_name(itemSource) # And if it's what we want, we yield it! if itemSourceName == sourceName: yield item
def playsound(filename, volume, speed): obs.script_log(obs.LOG_DEBUG, "Trying to play " + filename + " to source " + sourcename) scenesource = obs.obs_frontend_get_current_scene() scene = obs.obs_scene_from_source(scenesource) #obs.script_log(obs.LOG_DEBUG,"Scene "+str(scene)) sceneitem = obs.obs_scene_find_source(scene, sourcename) #obs.script_log(obs.LOG_DEBUG,"Scene item "+str(sceneitem)) source = obs.obs_sceneitem_get_source(sceneitem) obs.obs_source_set_volume(source, volume) set_source_speed(source, speed) obs.obs_sceneitem_set_visible(sceneitem, False) settings = obs.obs_source_get_settings(source) #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) obs.obs_data_set_string(settings, "local_file", audiofolder + filename) #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) obs.obs_source_update(source, settings) obs.obs_sceneitem_set_visible(sceneitem, True) obs.obs_data_release(settings) obs.obs_source_release(scenesource)
def get_audio_sources_from_scene(scene, source_dict=None): if source_dict is None: source_dict = OrderedDict() for sceneitem in obspython.obs_scene_enum_items( obspython.obs_scene_from_source(scene)): item_source = obspython.obs_sceneitem_get_source(sceneitem) name = obspython.obs_source_get_name(item_source) if obspython.obs_source_get_output_flags( item_source) & obspython.OBS_SOURCE_COMPOSITE: source_dict = get_audio_sources_from_scene(item_source, source_dict) if obspython.obs_source_get_output_flags( item_source) & obspython.OBS_SOURCE_AUDIO: source_active = obspython.obs_source_active(item_source) audio_active = obspython.obs_source_audio_active(item_source) priv_settings = obspython.obs_source_get_private_settings( item_source) hidden = obspython.obs_data_get_bool(priv_settings, "mixer_hidden") if not source_active or not audio_active or hidden: continue source_dict[name] = item_source return source_dict
def set_logo(blue_config, orange_config): #reused for logo later default_logo = os.path.join(files_path, 'logo.png') blue_config_bun = get_bot_config_bundle(blue_config) orange_config_bun = get_bot_config_bundle(orange_config) blue_logo = blue_config_bun.get_logo_file() if blue_logo is None: blue_logo = default_logo orange_logo = orange_config_bun.get_logo_file() if orange_logo is None: orange_logo = default_logo default_logo_scale = 0.25 default_logo_size = [400*default_logo_scale, 300*default_logo_scale] blue_logo_size = list(Image.open(blue_logo).size) blue_scale = default_logo_size[0]/blue_logo_size[0] orange_logo_size = list(Image.open(orange_logo).size) orange_scale = default_logo_size[0]/orange_logo_size[0] scenes = obs.obs_frontend_get_scenes() if scenes is not None: for scene in scenes: if obs.obs_source_get_name(scene) == 'RLBot - AutoLeague': scene = obs.obs_scene_from_source(scene) items = obs.obs_scene_enum_items(scene) for item in items: if item is not None: source_t = obs.obs_sceneitem_get_source(item) if obs.obs_source_get_name(source_t) == "Logo-0": source = source_t settings = obs.obs_data_create() obs.obs_data_set_string(settings, "file", blue_logo) obs.obs_source_update(source, settings) obs.obs_data_release(settings) vec = obs.vec2() obs.vec2_set(vec, blue_scale, blue_scale) obs.obs_sceneitem_set_scale(item, vec) if obs.obs_source_get_name(source_t) == "Logo-1": source = source_t settings = obs.obs_data_create() obs.obs_data_set_string(settings, "file", orange_logo) obs.obs_source_update(source, settings) obs.obs_data_release(settings) vec = obs.vec2() obs.vec2_set(vec, orange_scale, orange_scale) obs.obs_sceneitem_set_scale(item, vec) obs.source_list_release(scenes) obs.sceneitem_list_release(items)
def on_visibility_toggle(calldata): scenes_as_sources = obs.obs_frontend_get_scenes() sceneitem = obs.calldata_sceneitem(calldata, "item") visibility = obs.calldata_bool(calldata, "visible") name = obs.obs_source_get_name(obs.obs_sceneitem_get_source(sceneitem)) for scene_as_source in scenes_as_sources: scene = obs.obs_scene_from_source(scene_as_source) match = obs.obs_scene_find_source(scene, name) if match: obs.obs_sceneitem_set_visible(match, visibility) obs.source_list_release(scenes_as_sources)
def get_item_names_by_scene(source): item_names = [] scene = obs.obs_scene_from_source(source) scene_name = obs.obs_source_get_name(source) scene_items = obs.obs_scene_enum_items(scene) if scene_items is not None: for item in scene_items: item_source = obs.obs_sceneitem_get_source(item) item_name = obs.obs_source_get_name(item_source) if item_name in light_mapping: item_names.append(item_name) obs.sceneitem_list_release(scene_items) return item_names
def get_scene_item(name): scenes = obs.obs_frontend_get_scenes() if scenes is not None: for scene in scenes: if obs.obs_source_get_name(scene) == 'RLBot - AutoLeague': scene = obs.obs_scene_from_source(scene) items = obs.obs_scene_enum_items(scene) for item in items: if item is not None: scene_source = obs.obs_sceneitem_get_source(item) if obs.obs_source_get_name(scene_source) == name: sceneItem = obs.obs_scene_find_sceneitem_by_id(scene, obs.obs_sceneitem_get_id(item)) obs.source_list_release(scenes) obs.obs_sceneitem_addref(sceneItem) obs.sceneitem_list_release(items) return sceneItem obs.sceneitem_list_release(items) obs.source_list_release(scenes)
def set_names(source_name, string): scenes = obs.obs_frontend_get_scenes() if scenes is not None: for scene in scenes: if obs.obs_source_get_name(scene) == 'RLBot - AutoLeague': scene = obs.obs_scene_from_source(scene) items = obs.obs_scene_enum_items(scene) for item in items: if item is not None: source_t = obs.obs_sceneitem_get_source(item) if obs.obs_source_get_name(source_t) == source_name: source = source_t settings = obs.obs_data_create() obs.obs_data_set_string(settings, "text", str(string)) obs.obs_source_update(source, settings) obs.obs_data_release(settings) obs.source_list_release(scenes) obs.sceneitem_list_release(items)
def dumpSceneData(): scene = obs.obs_frontend_get_current_scene() sceneObject = obs.obs_scene_from_source(scene) items = obs.obs_scene_enum_items(sceneObject) itemArray = [] for item in items: sceneItem = obs.obs_sceneitem_get_source(item) name = obs.obs_source_get_name(sceneItem) if "tweentool:" not in name: pos = obs.vec2() obs.obs_sceneitem_get_pos(item, pos) rot = obs.obs_sceneitem_get_rot(item) scale = obs.vec2() obs.obs_sceneitem_get_scale(item, scale) alignment = obs.obs_sceneitem_get_alignment(item) bounds = obs.vec2() obs.obs_sceneitem_get_bounds(item, bounds) boundsType = obs.obs_sceneitem_get_bounds_type(item) boundsAlignment = obs.obs_sceneitem_get_bounds_alignment(item) crop = obs.obs_sceneitem_crop() obs.obs_sceneitem_get_crop(item, crop) itemArray.append({ "name": name, "pos": [pos.x, pos.y], "rot": rot, "scale": [scale.x, scale.y], "alignment": alignment, "bounds": [bounds.x, bounds.y], "boundsType": boundsType, "boundsAlignment": boundsAlignment, "crop": [crop.left, crop.right, crop.top, crop.bottom] }) return itemArray
def printSceneData(pressedState): if pressedState: nameOfTweener = None items = obs.obs_scene_enum_items( obs.obs_scene_from_source(obs.obs_frontend_get_current_scene())) for item in items: sceneItem = obs.obs_sceneitem_get_source(item) name = obs.obs_source_get_name(sceneItem) if "tweentool:" in name: nameOfTweener = name.split(':')[1] tweenTime = float(name.split(':')[3]) name = obs.obs_source_get_name(sceneItem) if nameOfTweener: print( json.dumps({ 'tweenName': nameOfTweener, 'length': tweenTime, 'tweenItems': dumpSceneData() })) else: print( 'Please create the appropriate source at the top of the source list for your naming. See instructions for further details.' )
def calculateNewScale(item, width, height): src = obs.obs_sceneitem_get_source(item) baseWidth = obs.obs_source_get_base_width(src) baseHeight = obs.obs_source_get_base_height(src) return (width / baseWidth), (height / baseHeight)
def calculateSize(scene_item, scaleX, scaleY): src = obs.obs_sceneitem_get_source(scene_item) baseWidth = obs.obs_source_get_base_width(src) baseHeight = obs.obs_source_get_base_height(src) return (int)(baseWidth * scaleX), (int)(baseHeight * scaleY)
def script_tick(seconds): # OBS script interface. global discord_source source_name = obs.obs_data_get_string(settings, 'discord_source') if source_name != obs.obs_source_get_name(discord_source): obs.obs_source_release( discord_source) # Doesn’t error even if discord_source == None. discord_source = obs.obs_get_source_by_name(source_name) if not client: return # NOTE: These are 0 when the source isn’t visible at all in the current scene. Not that it matters, but I was just weirded out by it until I got it. source_width = obs.obs_source_get_width(discord_source) source_height = obs.obs_source_get_height(discord_source) margin_top = MARGIN_TOP if not obs.obs_data_get_bool(settings, 'full_screen'): margin_top = margin_top + TITLE_BAR # Get Discord call layout distribution and caller size. people = [x for x in client.video] # Mutability and shiz. nonvideo = obs.obs_data_get_bool(settings, 'show_nonvideo_participants') if nonvideo: people += client.audio count = len(people) if count == 1 and (not client.audio or not client.video and nonvideo): count = 2 # Discord adds a call to action that occupies the same space as a second caller. rows = None cols = None width = 0 height = None offsetx = 0 offsety = 0 offset_last = None if source_width and source_height: totalw = source_width - MARGIN_SIDES * 2 totalh = source_height - margin_top - MARGIN_BTM if totalw > 0 and totalh > 0: wide = None # Discord packs the callers in as many columns as possible, unless their videos appear bigger with fewer columns. for c in reversed(range(1, count + 1)): r = math.ceil(count / c) w = (totalw - CALLER_SPACING * (c - 1)) / c h = (totalh - CALLER_SPACING * (r - 1)) / r wi = w / h > CALLER_ASPECT if wi: w = h * CALLER_ASPECT if w > width: rows = r cols = c width = w height = h wide = wi if rows: # If the window is wider or taller than the callers fit in, Discord will center them as a whole. inner_width = (width * cols + CALLER_SPACING * (cols - 1)) if wide: # Wider than needed, therefore center horizontally. offsetx = (totalw - inner_width) / 2 else: # Taller than needed, therefore center vertically. height = width / CALLER_ASPECT # We compared using widths only before, so height needs to be adjusted. offsety = (totalh - (height * rows + CALLER_SPACING * (rows - 1))) / 2 # If last row contains fewer callers than columns, Discord will center it. offset_last = count % cols if offset_last > 0: offset_last = (inner_width - (width * offset_last + CALLER_SPACING * (offset_last - 1))) / 2 # Apply necessary changes to relevant scene items. scene_sources = obs.obs_frontend_get_scenes() for scene_src in scene_sources: scene = obs.obs_scene_from_source(scene_src) # Shouldn’t be released. items = obs.obs_scene_enum_items(scene) i = 0 next_vis = None for item in reversed(items): _next_vis = None if obs.obs_sceneitem_get_source( item) == discord_source: # Shouldn’t be released. uid = int( obs.obs_data_get_string(settings, f'participant{i}') or -1) visible = True try: index = people.index(uid) except (IndexError, ValueError): visible = False i += 1 obs.obs_sceneitem_set_visible(item, visible) if visible and rows: crop = obs.obs_sceneitem_crop() obs.obs_sceneitem_get_crop(item, crop) scale = obs.vec2() obs.obs_sceneitem_get_scale(item, scale) bounds = obs.vec2() obs.obs_sceneitem_get_bounds(item, bounds) # If item was set to not use a bounding box policy, calculate it from its other transform properties. if obs.obs_sceneitem_get_bounds_type( item) == obs.OBS_BOUNDS_NONE: obs.vec2_set( bounds, scale.x * (source_width - crop.right - crop.left), scale.y * (source_height - crop.bottom - crop.top)) obs.obs_sceneitem_set_bounds(item, bounds) obs.obs_sceneitem_set_bounds_type( item, obs.OBS_BOUNDS_SCALE_OUTER) obs.obs_sceneitem_set_bounds_alignment( item, 0 ) # obs.OBS_ALIGN_CENTER doesn’t seem to be implemented. # Get top left corner of this caller. r = math.ceil((index + 1) / cols) c = index % cols + 1 x = MARGIN_SIDES + offsetx + (width + CALLER_SPACING) * (c - 1) if r == rows: x = x + offset_last y = margin_top + offsety + (height + CALLER_SPACING) * (r - 1) # Make sure the crop doesn’t overflow the item bounds. aspect = bounds.x / bounds.y clipx = 0 clipy = 0 if aspect > CALLER_ASPECT: clipy = (height - width / aspect) / 2 else: clipx = (width - height * aspect) / 2 crop.left = math.ceil(x + CALLER_BORDER + clipx) crop.top = math.ceil(y + CALLER_BORDER + clipy) crop.right = source_width - int(x + width - CALLER_BORDER - clipx) crop.bottom = source_height - int(y + height - CALLER_BORDER - clipy) obs.obs_sceneitem_set_crop(item, crop) sx = abs(scale.x) if uid == int( obs.obs_data_get_string(settings, 'myself') or -1) and uid in client.video: sx = -sx sy = scale.y obs.vec2_set(scale, sx, sy) obs.obs_sceneitem_set_scale(item, scale) if not nonvideo and obs.obs_data_get_bool( settings, 'item_right_below'): _next_vis = uid in client.audio elif next_vis is not None: obs.obs_sceneitem_set_visible(item, next_vis) next_vis = _next_vis obs.sceneitem_list_release(items) obs.source_list_release(scene_sources)
def cache_scenes(): global scene_win_map global cached_items global tagRegex global dimensions clear_cache() cached_num = 0 currentScene = obs.obs_frontend_get_current_scene() sceneName = obs.obs_source_get_name(currentScene) sceneObject = obs.obs_scene_from_source(currentScene) items = obs.obs_scene_enum_items(sceneObject) if items is not None: for item in items: source = obs.obs_sceneitem_get_source(item) source_id = obs.obs_source_get_id(source) source_name = obs.obs_source_get_name(source) #find = re.match(tagRegex, source_name) #print(tagRegex, source_name) if (re.match(tagRegex, source_name) and source_id == "window_capture"): modifiers = {} flagsSearch = re.findall(tagRegex, source_name) flags = flagsSearch[0].split(",") for flag in flags: modifiers[flag.lower()] = True data = obs.obs_source_get_settings(source) windowData = obs.obs_data_get_string(data, "window") windowSplit = windowData.split(":") windowTitle = windowSplit[0].replace("#3A", ":") #print("Window Title: " + windowData[0]) #print("Window EXE: " + windowData[1]) obs.obs_data_release(data) try: if (windowData in scene_win_map): myWin = scene_win_map[windowData] else: myWin = win.FindWindow(None, windowTitle) scene_win_map[windowData] = myWin except: pass cached_items[cached_num] = { "item": item, "source": source, "modifiers": modifiers, "win32gui": myWin } cached_num += 1 else: #obs.obs_source_release(source) obs.obs_sceneitem_release(item) pass #obs.obs_source_release(source) #obs.obs_sceneitem_release(item) obs.obs_scene_release(sceneObject) #obs.obs_source_release(currentScene) #print("Cached %d items." % (cached_num)) dimensions = obs.obs_video_info() obs.obs_get_video_info(dimensions)
def script_tick(tick): if scriptSettings['anim']['animating']: scriptSettings['anim']['time'] += tick scriptSettings['anim']['time'] = min(scriptSettings['anim']['time'], scriptSettings['anim']['length']) initial = scriptSettings['anim']['src'] destination = scriptSettings['anim']['dest'] tScale = easeInOutQuad( scriptSettings['anim']['time'] / scriptSettings['anim']['length'], 0, 1, 1) scene = obs.obs_frontend_get_current_scene() sceneObject = obs.obs_scene_from_source(scene) tweenItems = scriptSettings['anim']['tweener']['tweenItems'] sceneItems = obs.obs_scene_enum_items(sceneObject) for sItem in sceneItems: sceneItem = obs.obs_sceneitem_get_source(sItem) sName = obs.obs_source_get_name(sceneItem) for tItem in tweenItems: if sName == tItem['name']: pos = obs.vec2() pos.x = tScale * ( destination[sName]["pos"][0] - initial[sName]["pos"][0]) + initial[sName]["pos"][0] pos.y = tScale * ( destination[sName]["pos"][1] - initial[sName]["pos"][1]) + initial[sName]["pos"][1] rot = tScale * (destination[sName]["rot"] - initial[sName] ["rot"]) + initial[sName]["rot"] scale = obs.vec2() scale.x = tScale * (destination[sName]["scale"][0] - initial[sName]["scale"][0] ) + initial[sName]["scale"][0] scale.y = tScale * (destination[sName]["scale"][1] - initial[sName]["scale"][1] ) + initial[sName]["scale"][1] alignment = destination[sName]["alignment"] bounds = obs.vec2() bounds.x = tScale * (destination[sName]["bounds"][0] - initial[sName]["bounds"][0] ) + initial[sName]["bounds"][0] bounds.y = tScale * (destination[sName]["bounds"][1] - initial[sName]["bounds"][1] ) + initial[sName]["bounds"][1] boundsType = destination[sName]["boundsType"] boundsAlignment = destination[sName]["boundsAlignment"] crop = obs.obs_sceneitem_crop() crop.left = math.floor(tScale * (destination[sName]["crop"][0] - initial[sName]["crop"][0]) + initial[sName]["crop"][0]) crop.right = math.floor(tScale * (destination[sName]["crop"][1] - initial[sName]["crop"][1]) + initial[sName]["crop"][1]) crop.top = math.floor(tScale * (destination[sName]["crop"][2] - initial[sName]["crop"][2]) + initial[sName]["crop"][2]) crop.bottom = math.floor(tScale * (destination[sName]["crop"][3] - initial[sName]["crop"][3]) + initial[sName]["crop"][3]) obs.obs_sceneitem_set_pos(sItem, pos) obs.obs_sceneitem_set_rot(sItem, rot) obs.obs_sceneitem_set_scale(sItem, scale) obs.obs_sceneitem_set_alignment(sItem, alignment) obs.obs_sceneitem_set_bounds(sItem, bounds) obs.obs_sceneitem_set_bounds_type(sItem, boundsType) obs.obs_sceneitem_set_bounds_alignment( sItem, boundsAlignment) obs.obs_sceneitem_set_crop(sItem, crop) if scriptSettings['anim']['time'] >= scriptSettings['anim']['length']: scriptSettings['anim']['src'] = None scriptSettings['anim']['dest'] = None scriptSettings['anim']['time'] = math.inf scriptSettings['anim']['length'] = 10000 scriptSettings['anim']['tweener'] = None scriptSettings['anim']['animating'] = False