import requests import hogumathi_app.content_system as h_cs import hogumathi_app.view_model as h_vm VIDEOS_APP="http://localhost:5006" def get_video_collections (): url = f'{VIDEOS_APP}/channels.json' resp = requests.get(url) return resp.json() def get_video_collection (collection_id): url = f'{VIDEOS_APP}/channel/{collection_id}/videos.json' resp = requests.get(url) coll_data = resp.json()['data'] def to_feed_item (c): if c['media']['is_archived']: video = h_vm.MediaItem( type = 'video', preview_image_url = c['poster'], url = c['media']['url'], content_type = c['media']['type'], width = c['media']['width'] or 480, height = c['media']['height'] or 360, duration_ms = int(c['duration']) * 1000 ) else: video = h_vm.MediaItem( type = 'video', preview_image_url = c['poster'], url = c['media']['embed_url'], content_type = c['media']['type'], width = c['media']['width'] or 480, height = c['media']['height'] or 360, duration_ms = int(c['duration']) * 1000 ) fi = h_vm.FeedItem( id = c['guid'], handle = coll_data['id'], display_name = c['author'], created_at = c['pub_date'], videos = [video], title = c['title'], text = c['description'], url = c['link'], author_url = c['author_url'], source_url = c['source_link'] ) return fi feed_items = list(map(to_feed_item, coll_data['items'])) return feed_items def test_video_collection (): colls = get_video_collections() print(colls['data'][32].keys()) coll = get_video_collection(colls['data'][32]['id']) return coll #print(coll['data']['items'][1].keys()) #print(coll['data']['items'][1]['media']) def search_videos_cards_collection (q, collection_id): # FIXME cards may not be the best format but it's all we support url = f'{VIDEOS_APP}/videos/search.cards.json' params = dict( channel = collection_id, q = q ) # card logic from search note cards. resp = requests.get(url, params=params) if resp.status_code != 200: return resp_json = resp.json() cards = resp_json['cards'] def to_feed_item (search_result): # different from normal collection # FIXME this uses Os-specific path sep channel_and_video_id = search_result['id'] # FIXME not provided by videos_app yet #video_channel = search_result['channel'] c = search_result['card'] card_id = c['id'] # work-around since search result ID also includes channel video_id = card_id #content_url = f'{NOTES_APP}/notes/{collection_id}.html#note={note_id}&card={card_id}' # FIXME we need to update notes app to include the collection_id #content_url = c['content_source'].replace(':notes-app', NOTES_APP) #content_url += f'&card={card_id}' content_url = f'{VIDEOS_APP}/channel/{collection_id}/video/{video_id}.html' source_url = c['content_source'] fi = h_vm.FeedItem( id = card_id, display_name = "Notes App", handle = collection_id, created_at = c['created_at'], title = c['title'], text = c['content'], url = content_url, source_url = source_url ) return fi feed_items = list(map(to_feed_item, cards)) return feed_items NOTES_APP = 'http://localhost:5000' def get_note_cards_collection (note_id, collection_id='daily'): """ This is a good use case where we could directly query models, Rather than over HTTP. Store or Service Layer needs to support multi-process locking or similar. """ url = f'{NOTES_APP}/{collection_id}/note/{note_id}/cards' resp = requests.get(url) if resp.status_code != 200: return resp_json = resp.json() cards = resp_json['cards'] def to_feed_item (c): card_id = c['id'] note_id = c['note_id'] content_url = f'{NOTES_APP}/notes/{collection_id}.html#note={note_id}&card={card_id}' # FIXME we need to update notes app to include the collection_id #content_url = c['content_source'].replace(':notes-app', NOTES_APP) #content_url += f'&card={card_id}' fi = h_vm.FeedItem( id = card_id, display_name = "Notes App", handle = collection_id, created_at = c['created_at'], title = c['title'], text = c['content'], url = content_url ) return fi feed_items = list(map(to_feed_item, cards)) return feed_items #@h_cs.query("notes:cards:search", weight=1000) def search_note_cards_collection (q, collection_id='daily'): url = f'{NOTES_APP}/{collection_id}/notes/cards/search' params = dict( q = q ) resp = requests.get(url, params=params) if resp.status_code != 200: return resp_json = resp.json() cards = resp_json['cards'] def to_feed_item (search_result): # different from normal collection c = search_result['card'] # FIXME we should add this to notes_app #note_id = search_result['id'] card_id = c['id'] note_id = c['note_id'] content_url = f'{NOTES_APP}/notes/{collection_id}.html#note={note_id}&card={card_id}' # FIXME we need to update notes app to include the collection_id #content_url = c['content_source'].replace(':notes-app', NOTES_APP) #content_url += f'&card={card_id}' fi = h_vm.FeedItem( id = card_id, display_name = "Notes App", handle = collection_id, created_at = c['created_at'], title = c['title'], text = c['content'], url = content_url ) return fi feed_items = list(map(to_feed_item, cards)) return feed_items #@h_cs.command("notes:cards:collection:prepend:", weight=1000) def post_notes_card_prepend (note_id, text, collection_id='daily', should_create=True): """ This is no different than posting a Tweet. Logically adds an item to the beginning of the collection. In the near future the intents will be manually approved but for now it's just a normal write. We might need to add a token of some sort as well for auth. """ url = f'{NOTES_APP}/{collection_id}/intent/prepend-text/{note_id}' params = dict( text = text, should_create = should_create ) resp = requests.get(url, params=params) return def get_librivox_books (): """ https://librivox.org/api/info """ pass def register_content_sources (): """ bitchute:channel: bitchute:video: bitchute:profile:user: bitchute:videos:channel: bitchute:comments:video: """ h_cs.register_content_source("notes:cards:collection:", get_note_cards_collection, id_pattern="([^:]+)") h_cs.register_content_source("notes:cards:search", search_note_cards_collection, id_pattern="") #h_cs.register_content_command("notes:cards:collection:prepend", post_notes_card_prepend) #h_cs.register_content_query("notes:cards:search", search_note_cards_collection, id_pattern="") # h_cs.register_content_source("videos:collection:", get_video_collection, id_pattern="([^:]+)") h_cs.register_content_source("videos:cards:search", search_videos_cards_collection, id_pattern="") def get_bitchute_comments (): """ script initComments( 'https://commentfreely.bitchute.com', 'eyJwcm9maWxlX2lkIjogImFub255bW91cyIsICJvd25lcl9pZCI6ICJ2UkI1eFpXVW5EYlAiLCAiZGlzcGxheV9uYW1lIjogImFub255bW91cyIsICJ0aHJlYWRfaWQiOiAiYmNfMnFDQ3dyWm9kcXVxIiwgImljb25fdXJsIjogIi9zdGF0aWMvdjE0MS9pbWFnZXMvYmxhbmstcHJvZmlsZS5wbmciLCAiY2ZfaXNfYWRtaW4iOiAiZmFsc2UiLCAiY2hhbm5lbF9pZCI6ICJhZ0R1aVcxQWhXeHoifQ== 1f280c339d11ce063d204d66f4fe38fa938474290994899d5128d3a2ee79c471 1679618698', 'anonymous' function initComments(cf_url, cf_auth, currentUserId, profilePictureURL, commentCountDeprecated, refreshAction, isThreadAdmin, isSupporter, isBlocked) { getComments: function(success, error) { var isFirstCall = !window.getCommentsTime; getCommentsTime = Date.now(); $.ajax({ type: 'post', url: cf_url + '/api/get_comments/', data: { cf_auth: cf_auth, commentCount: (isFirstCall) ? 0 : localCommentCount || -1, isNameValuesArrays: true }, success: function(comments) { localCommentCount = comments.values.length; commentCount = comments.normalizedCommentCount; lastCallTime = comments.callTime; dynamicCacheSeconds = comments.dynamicSeconds; success(comments) }, e Request headers: authority: commentfreely.bitchute.com origin: https://www.bitchute.com referer: https://www.bitchute.com/ content-type: application/x-www-form-urlencoded; charset=UTF-8 Response { "names": [ "id", "parent", "created", "modified", "content", "pings", "creator", "fullname", "created_by_admin", "created_by_current_user", "up_vote_count", "down_vote_count", "user_vote", "is_new", "profile_picture_url", "attachments" ], "values": [ [ "0LAnLMLmA66dSLbK0ur25CPoPITCsId9eE46", null, "2023-03-24 00:19:44.371714+00:00", null, "Love you Blue", [], "mW6Q8LlCDs7Y", "Joelkenimer", false, false, 5, 2, null, false, "/static/v141/images/blank-profile.png", [] ], [ "k9KG622jF7IJ6bJvOiqpE9HdYgvl254DbE3M", null, "2023-03-24 00:22:12.367094+00:00", null, "OK pls send us a link for Odysee if that happens.", [], "OTjfEnZ1HrAC", "danortego", false, false, 8, 0, null, false, "/static/v141/images/blank-profile.png", [] ], [ "z3EdQTt21UCVmqeeymvuN0BV1vnvJpTs4COR", null, "2023-03-24 00:23:40.374960+00:00", null, "I'm very happy about that C21 and Ryu", [], "qgjwPrLKPkDN", "MayQ", false, false, 4, 1, null, false, "/static/v141/images/blank-profile.png", [] ], [ "wdGCZbdx9aCwZ4fDGvAg0tk58wEKS1L481Te", null, "2023-03-24 00:24:06.963831+00:00", null, "What is Odysee?", [], "NNTNz25N0fwU", "eseme", false, false, 3, 1, null, false, "/static/v141/images/blank-profile.png", [] ], [ "69qwpTIezaJCb0AHunNBghQMPFcXWowWWiK0", null, "2023-03-24 00:24:10.178391+00:00", null, "I am really starting to get why this has to be a soft exposure! The normies are going to literally freak the FARK out! Thanks BW your dedication to getting this out is truly appreciated!", [], "vcWaw0oRGYPZ", "3nd5laveryQ", false, false, 6, 1, null, false, "https://static-3.bitchute.com/live/profile_images/vcWaw0oRGYPZ/nhl3wJhdEu8OYdvTaGOVXBy7_medium.jpg", [] ], [ "wr5uoJppgCBrHn21eIydrAEHQ6ZEhn7nn7tR", null, "2023-03-24 00:25:43.415416+00:00", null, "Thank you to both Christian21 and bluewater. I'm glad that Ryushin apologized, we all make mistakes, none of us is perfect.", [], "7EVG4eljblWD", "kg78bv2", false, false, 5, 1, null, false, "/static/v141/images/blank-profile.png", [] ], [ "2bNNBVb6ySQ0tNHkNoURaWavXPyL6tmE0dkP", "wdGCZbdx9aCwZ4fDGvAg0tk58wEKS1L481Te", "2023-03-24 00:27:15.508892+00:00", null, "It is an app like Rumble and BitChute that Bluewater is on.", [], "DAu6hPe36k5K", "PJStitcher", false, false, 2, 1, null, false, "/static/v141/images/blank-profile.png", [] ], [ "opFpX4MxSdZYMgXn7m0V8HFoahZ9TOF3XIwd", null, "2023-03-24 00:32:36.503395+00:00", null, "💜💜💜", [], "zC9exgm75dJG", "Janeybell", false, false, 1, 0, null, false, "/static/v141/images/blank-profile.png", [] ], [ "1XEXyQ5Gs8Wqi7JNCMIqpivvMcwfl5jEKZKV", null, "2023-03-24 00:34:58.928846+00:00", null, "Thank you for this Blue and Christian21!", [], "b1cOBqmTurdZ", "fuchsia", false, false, 0, 0, null, false, "https://static-3.bitchute.com/live/profile_images/b1cOBqmTurdZ/pfykURW9xNIULWdFaCNtQQoa_medium.jpg", [] ], [ "j4VhOHiDfCFzY78XWr7FyxjCZV3Fcxmt9ORd", "wdGCZbdx9aCwZ4fDGvAg0tk58wEKS1L481Te", "2023-03-24 00:36:22.977951+00:00", null, "https://odysee.com/@Bluewater:e", [], "S39g9uIZsV8L", "lupin in the green", false, false, 1, 0, null, false, "https://static-3.bitchute.com/live/profile_images/S39g9uIZsV8L/E61gvkIIRWiJQE2aNducAcuv_medium.jpg", [] ] ], "callTime": "1679618290.1224425", "dynamicSeconds": 300, "normalizedCommentCount": 10, "isUniversalPin": false, "pinnedCommentId": null } """ pass