简体   繁体   English

将 Microsoft Teams 聊天导出到文件以进行存档

[英]Export Microsoft Teams chat to file for archiving

Has anyone ever managed to save an entire chat from Microsoft Teams in any file format (including chat images eg screenshots, user avatars etc.)?有没有人设法以任何文件格式保存来自 Microsoft Teams 的整个聊天记录(包括聊天图像,例如屏幕截图、用户头像等)?

I've tried it in all browsers and in all thinkable ways.我已经在所有浏览器中以所有可以想到的方式尝试过它。

The problem seems to be that Teams removes all text not contained in the current viewport, and even more so the images, from memory.问题似乎是 Teams 从 memory 中删除了当前视口中未包含的所有文本,甚至更多的是图像。

This looks like lazy loading , but apparently isn't, as it can't be prevented by disabling the lazy loading options in the browser (tried in Chrome and Firefox, with the browser-based version of Teams).这看起来像lazy loading ,但显然不是,因为它不能通过禁用浏览器中的延迟加载选项来阻止(在 Chrome 和 Firefox 中尝试过,使用基于浏览器的 Teams 版本)。

Only the content of the current viewport is displayed and loaded.仅显示和加载当前视口的内容。 All other content further up as well as further down is immediately unloaded when scrolling.滚动时,所有其他向上和向下的内容都会立即卸载。 Therefore, the entire chat cannot be selected and saved or exported, respectively, in any way, and not even be copied to the clipboard:因此,无法以任何方式分别选择和保存或导出整个聊天,甚至无法将其复制到剪贴板:

Contents outside the viewport are unloaded immediately when scrolling滚动时立即卸载视口外的内容

Here's some spaghetti I came up with that works in Chrome console -- it scrolls to the top of whatever chat you have selected, and then goes piece by piece down the line, creating a printable/savable copy.这是我想出的一些可在 Chrome 控制台中使用的意大利面——它会滚动到您选择的任何聊天的顶部,然后逐条逐行创建一个可打印/可保存的副本。 Even loads all the inline pictures.甚至加载所有内嵌图片。

Only issue is that really long chat histories take a while to scroll to beginning of.唯一的问题是真的很长的聊天记录需要一段时间才能滚动到开头。

So yeah, to use, just open Chrome console window (Ctrl+Shift+J) copy-and-paste this in, and press enter.所以是的,要使用,只需打开Chrome 控制台窗口(Ctrl+Shift+J),将其复制并粘贴到其中,然后按 Enter。 Then wait for it to do the magics.然后等待它施展魔法。

let xxx = 0;
let ddd = 0;
let fullpage1 = '' 

fullpage1 = '<h1 id="chat-header-title2">'+jQuery('#chat-header-title').html()+'</h1>';

//**********************************************
//Go to top of page

jj234 = function() {


jQuery("virtual-repeat").scrollTop(-2000);



if (xxx < 50) {setTimeout(jj234, 50); } else {setTimeout(ScrollDownTakeNote, 1000); }

if (jQuery("virtual-repeat").hasClass("not-at-top")) {xxx = 0;} else {xxx += 1;} 

}

jj234();


//Create a place to hold a copy of the content
jQuery("body").append('<div id="thebigdiv" style="z-index: 10000; overflow: auto; background: white;"></div>');


//*************************************************
//Scroll down the chat, once things load, copy it to the temp location, removing some dynamic content

ScrollDownTakeNote = function() {

if (jQuery('.disable-event').length==0 && jQuery('.ts-image .loading').length==0) {
ddd += 1;

jQuery("#thebigdiv").append('<div id="boxdiv'+ddd+'"></div>');

jQuery("virtual-repeat div.clearfix").each( function () {
jQuery("#boxdiv"+ddd).append('<div class="messageClip" id="'+jQuery(this).attr('id')+'">' + jQuery(this).html() + '</div>');
});

jQuery("#boxdiv"+ddd+" [data-tid]").attr("data-tid","");

jQuery("#boxdiv"+ddd+" [ng-if]").attr("ng-if","");

jQuery("#boxdiv"+ddd+" [ng-class]").attr("ng-class","");

jQuery("#boxdiv"+ddd+" [ng-source]").attr("ng-source","");

jQuery("#boxdiv"+ddd+" [ng-class]").attr("ng-class","");

jQuery("#boxdiv"+ddd+" [simple-mouseenter]").attr("simple-mouseenter","");

jQuery("#boxdiv"+ddd+" [ng-mouseleave]").attr("ng-mouseleave","");

jQuery("#boxdiv"+ddd+" [message-view-model]").attr("message-view-model","");

jQuery("#boxdiv"+ddd+" [message-vm]").attr("message-vm","");

jQuery("#boxdiv"+ddd+" [is-enabled]").attr("is-enabled","");

jQuery("#boxdiv"+ddd+" [host-tenant-id]").attr("host-tenant-id","");


jQuery("#boxdiv"+ddd+" [scroll-item-tracker]").attr("scroll-item-tracker","");
jQuery("#boxdiv"+ddd+" [scroll-item-id]").attr("scroll-item-id","");
jQuery("#boxdiv"+ddd+" [scroll-item-event-name]").attr("scroll-item-event-name","");
jQuery("#boxdiv"+ddd+" [is-above-view-callback]").attr("is-above-view-callback","");
jQuery("#boxdiv"+ddd+" [is-in-view-callback]").attr("is-in-view-callback","");
jQuery("#boxdiv"+ddd+" [scroll-container]").attr("scroll-container","");
jQuery("#boxdiv"+ddd+" [check-above-viewport]").attr("check-above-viewport","");
jQuery("#boxdiv"+ddd+" [delay-scroll-tracker-init]").attr("delay-scroll-tracker-init","");
jQuery("#boxdiv"+ddd+" [deferred-render-ready]").attr("deferred-render-ready","");

jQuery("#boxdiv"+ddd+" img[target-src]").each(function () {$(this).attr("lazy-load","false"); $(this).attr("src",$(this).attr("target-src"));});

jQuery("#boxdiv"+ddd+" skype-status").remove();

fullpage1 += jQuery("#thebigdiv").html();
jQuery("#thebigdiv").html(".");

jQuery("virtual-repeat.simple-scrollbar").scrollTop(jQuery("virtual-repeat.simple-scrollbar").scrollTop()+2000);

}

if  (jQuery('[data-scroll-pos="1"').length==0 || jQuery("virtual-repeat").hasClass("not-at-bottom") || jQuery('.disable-event').length>0 || jQuery('.ts-image .loading').length>0 ) {setTimeout(ScrollDownTakeNote, 500);
} else {printdiv("#thebigdiv")}

};

//**********************************
//Open a Save File dialog for the HTML source and open the print window for a Print-to-PDF
//(Why not both?)

function printdiv(printdivname) {
        jQuery(printdivname).html(fullpage1);
    jQuery('#outer-shell').remove();
    jQuery('body').css({"overflow":"scroll"});
    
    $('div.messageClip[id]').each(function () {
            $('div.messageClip[id="' + this.id + '"]:gt(0)').remove();
    });
    jQuery(printdivname).css({"margin-left":"15px"});
    jQuery('body').append("<style>@media print { * { overflow: visible !important; } .page { page-break-after:always; }}");
    jQuery('head').append('<link rel="stylesheet" href="https://statics.teams.cdn.office.net/hashed/stylesheets.theme-defaultV2.min-86505e7.css" />');
    
    fullpage2 = new XMLSerializer().serializeToString(document);
    //fullpage2 = fullpage2.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
    //  return '&#'+i.charCodeAt(0)+';'; 
    //});

    saveTextAsFile(fullpage2);  

    waitonimages();
    
}

let xasd = 0;
function waitonimages() {
    xasd = 0;
    jQuery("img").each(function () {if (!this.complete) { xasd+=1 }});
    if (xasd == 0) {window.print()} else {setTimeout(waitonimages,1000);}   
}

function saveTextAsFile(text1)
{
    //inputTextToSave--> the text area from which the text to save is
    //taken from
    var textToSave = text1;
    var textToSaveAsBlob = new Blob([textToSave], {type:"text/html"});
    var textToSaveAsURL = window.URL.createObjectURL(textToSaveAsBlob);
    //inputFileNameToSaveAs-->The text field in which the user input for 
    //the desired file name is input into.
    var fileNameToSaveAs = jQuery('#chat-header-title2').html() + "-source.htm";

    var downloadLink = document.createElement("a");
    downloadLink.download = fileNameToSaveAs;
    downloadLink.innerHTML = "Download File";
    downloadLink.href = textToSaveAsURL;
    downloadLink.onclick = destroyClickedElement;
    downloadLink.style.display = "none";
    document.body.appendChild(downloadLink);

    downloadLink.click();
}

function destroyClickedElement(event)
{
    document.body.removeChild(event.target);
}

I ran into the same problem.我遇到了同样的问题。 I couldn't use the graph API since my user does not have the permissions (just a normal Teams user).我无法使用图形 API,因为我的用户没有权限(只是一个普通的 Teams 用户)。

I also noticed the sort of "Lazy loading" you mention so a solution I found was to extend the view so everything is visible (and loaded).我还注意到您提到的那种“延迟加载”,因此我找到的解决方案是扩展视图,以便所有内容都可见(并加载)。

I did this with the Firefox console commands suggested here :我使用此处建议的 Firefox 控制台命令执行此操作

  1. Make sure that you scrolled to the top and the bottom of the chat conversation you want to save确保您滚动到要保存的聊天对话的顶部和底部
  2. Press F12 to open the developer tools按F12打开开发者工具
  3. Select the tab "Console" in the developer tools在开发者工具中选择“控制台”选项卡
  4. Paste the code below in the console, it should zoom out the page将下面的代码粘贴到控制台中,它应该缩小页面
const zoomFactor = (document.querySelector(".ts-main-flex").offsetHeight / document.querySelector(".list-wrap").offsetHeight); document.documentElement.style.setProperty("transform", "scale(" + zoomFactor + ")"); document.documentElement.style.setProperty("transform-origin", "top"); document.documentElement.style.setProperty("min-height", (100 / zoomFactor) + "vh");
  1. Once the page is fully loaded, paste the code below in the console, it should expand all the grouped chats.页面完全加载后,将下面的代码粘贴到控制台中,它应该展开所有分组聊天。
 document.querySelectorAll(".expand-collapse").forEach(link => link.click()); document.querySelectorAll(".ts-see-more-button.ts-see-more-fold").forEach(link => link.click());
  1. Paste the code below in the console, it should adjust the zoom level将下面的代码粘贴到控制台中,它应该调整缩放级别
const newZoomFactor = (document.querySelector(".ts-main-flex").offsetHeight / document.querySelector(".list-wrap").offsetHeight); document.documentElement.style.setProperty("transform", "scale(" + newZoomFactor + ")"); document.documentElement.style.setProperty("min-height", (100 / newZoomFactor) + "vh");
  1. Once the page is fully loaded, paste the code below to reset the zoom and add a scrollbar页面完全加载后,粘贴下面的代码以重置缩放并添加滚动条
document.documentElement.style.removeProperty("transform"); document.documentElement.style.removeProperty("transform-origin"); document.documentElement.style.setProperty("overflow", "auto");
  1. Save the page with SingleFile使用 SingleFile 保存页面
  2. Take a coffee, enjoy the passing of time, pray for your CPU喝杯咖啡,享受时光的流逝,为你的CPU祈祷
  3. And voilà!瞧! Your saved page should be okay您保存的页面应该没问题

Saving the page with SingleFile worked great for me.使用 SingleFile 保存页面对我来说非常有用。

For very long chats I used SingleFileZ which is a fork of SingleFile that adds compression and generates an auto-extracting file.对于很长的聊天,我使用了 SingleFileZ,它是 SingleFile 的一个分支,它增加了压缩并生成了一个自动解压缩文件。 In these cases some of the steps took me a few hours to complete.在这些情况下,有些步骤需要我几个小时才能完成。

You can get teams chat using graph API along with the images but it is limited only for 20 days data.您可以使用图形 API和图像进行团队聊天,但仅限于 20 天的数据。 You can fetch the teams chat up to 20 days.您最多可以获取 20 天的团队聊天记录。 Also There is an feature request to export the teams chat externally.还有一个功能请求可以将团队聊天导出到外部。 Currently you cannot export teams chat.目前您无法导出团队聊天。 Could you please upvote Teams chat history export feature to available this in future.您能否为 Teams 聊天记录导出功能点赞, 以便将来可以使用。 You can reach out to Product support channels for more info您可以联系产品支持渠道了解更多信息

I found opening the Teams chat in the browser lets you select and copy-paste multiple messages and images in the conversation.我发现在浏览器中打开 Teams 聊天可以让你在对话中选择和复制粘贴多条消息和图像。

next: use regex-replace in the destination (MS Word) file to remove all the meta-information (timestamp + name).下一步:在目标(MS Word)文件中使用regex-replace删除所有元信息(时间戳+名称)。

Replace '[???????????????????????'代替 '[???????????????????????' with ''和 ''

The easiest and best way for me on not too long chats was opening the chat in the Opera browser, then zooming out as much as possible until the entire chat is visible in tiny size, and then saving the page to PDF.对于不太长的聊天,对我来说最简单和最好的方法是在 Opera 浏览器中打开聊天,然后尽可能地缩小直到整个聊天都以很小的尺寸可见,然后将页面保存到 PDF。

This way, you get a PDF of the chat with high quality vector text and images.这样,您将获得 PDF 的高质量矢量文本和图像聊天记录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在聊天应用程序中使用带有contentoffset的uitableview进行延迟加载 - Lazy loading with uitableview with contentoffset in a chat application 聊天列表视图停止刷新图像视图 - Chat listview stop refreshing image views PrimeFaces从Lazyloading DataTable导出数据 - PrimeFaces Export data from a Lazyloading DataTable 模块未定义用于从外部包动态导入命名导出 - Module is undefined for dynamic import of a named export from an external package 如何在PrimeFaces中使用延迟加载页面表导出数据? - How to export data with lazy loading page table in PrimeFaces? 什么是Microsoft Entity Framework中的DeferredLoading和LazyLoading? - What are DeferredLoading and LazyLoading in Microsoft Entity Framework? 如何将MEF导入和导出信息保存到磁盘 - How to persist MEF import and export information to disk 懒惰地阅读D中的文件 - Lazily Reading a File in D 如何在 React 应用程序中使用 webpack 代码拆分,组件导出为 export * from '...' - How to use code splitting with webpack in react app with components exported as export * from '...' Python将变量定义为“首次使用时加载文件” - Python define variable as “load file at first use”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM